有意思的题目

代码为佬的代码,学习思路
https://blog.csdn.net/2403_87718362/article/details/148305919?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522e7ec590509d30ae289c44b5ee4e03133%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=e7ec590509d30ae289c44b5ee4e03133&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-1-148305919-null-null.142v102control&utm_term=codeforces%20round%201027&spm=1018.2226.3001.4187
https://codeforces.com/contest/2114/problem/F

这道题目很容易想到想将x -> gcd(x, y), 第二步就是 x -> y, 主要问题就是x / gcd(x, y) 以及 y / gcd(x, y)可能超过k
这时候就需要将除数x / gcd(x, y) 划分为若干个小于等于k的因数使得凑到x / gcd(x, y)的值,同理x -> y也是凑y / gcd(x, y)
的步骤,但是怎么凑呢。
需要用到仔细想一想可以发现可以变成划分子问题的问题。问题是从1凑到x / gcd(x, y)的因数不超过k的最少次数。
先将所有的约数找到,然后使用动态规划,求出需要凑出各约数的最小值,然后整理答案

这道题目其实应该算我第一次遇到的数论中结合动态规划的题目了,有点新奇有点意思,留下做个纪念。

代码:


#include 
#include 
#include 
using namespace std;
typedef long long LL;

LL gcd(LL a, LL b)
{
    return b == 0 ? a : gcd(b, a % b);
}
 
LL get_ans(LL x, LL k)
{
    if(x == 1) return 0;
    //这里是求x所有的约数,后面的动态规划需要使用到。
    vector fac;
    for(int i = 1; i * i <= x; i++)
    {
        if(x % i == 0) 
        {
            fac.push_back(i);
            if(x / i != i) fac.push_back(x / i);
        }
    }
    sort(fac.begin(), fac.end());
    int n = fac.size();
    vector dp(n, 100);//dp数组定义为从1到fac[i]所需要的最小不超过k的因数乘积次数。
    dp[0] = 0;//1需要的到1的为0.
    for(int i = 1; i < n; i++)
    {
        for(int j = i - 1; j >= 0; j--)
        {
            if(fac[i] / fac[j] > k) break;//j就是从fac[i]的第一个小于fac[i]的数开始确保一次乘法不会超过k,无论除不除的尽。
            else
            {
                if(fac[i] % fac[j] == 0) 
                    dp[i] = min(dp[i], dp[j] + 1);
            }
        }
    }
    return dp[n - 1] == 100 ? -1 : dp[n - 1];
}
 
void solve() 
{
    LL x, y, k; cin >> x >> y >> k;
    LL g = gcd(x, y);
    LL ans = 0;
    x = x / g;
    y = y / g;
    LL ax = get_ans(x, k);
    LL ay = get_ans(y, k);
    if(ax == -1 || ay == -1) cout << -1 << endl;
    else cout << ax + ay << endl;
 
}
 
 
int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T;
	cin >> T;
	while(T--)
	{
        solve();
	}
	return 0;
}

https://codeforces.com/contest/2114/problem/D

题目思路大致是,给你n个位置坐标,你可以移动至多一个位置到任意坐标,问你最小的矩形可以包括所有的n个坐标,思路也很简单就想到,要移动也是移动边界点也就是横坐标最靠左边或者最靠右边,纵坐标最考上,或者最靠下面,可以通过排序得到删除这个最上面或者最下面或者最左边或者最右边的点,得到的最小包括矩阵,同时如果最小包括矩阵如果面积刚好等于n - 1就表示移动的边界点无法放入,就需要加一行或者一列,哪个需要的代价少加哪一个。
代码如下:


#include 
#include 
#include 
using namespace std;
typedef long long LL;
#define endl '\n'
 
const int N = 2e5 + 10;
struct node
{
    LL x, y;
}a[N], b[N];
int n; 
bool cmp1(node& a, node& b)
{
    return a.x < b.x;
}
 
bool cmp2(node& a, node& b)
{
    return a.y < b.y;
}
 
LL calc()
{
    LL ans = 4e18;
    LL r = 0, l = 2e9, d = 2e9, u = 0;
    for(int i = 2; i <= n; i++)
    {
        LL x = a[i].x, y = a[i].y;
        l = min(l, x); r = max(r, x);
        d = min(y, d); u = max(u, y);
    }
    LL ret = (abs(r - l) + 1) * (abs(u - d) + 1);
    if(ret == n - 1) ret += min(abs(r - l) + 1, abs(u - d) + 1);
    ans = min(ans, ret);
    r = 0, l = 2e9, d = 2e9, u = 0;
    for(int i = 1; i <= n - 1; i++)
    {
        LL x = a[i].x, y = a[i].y;
        l = min(l, x); r = max(r, x);
        d = min(y, d); u = max(u, y);
    }  
    ret = (abs(r - l) + 1) * (abs(u - d) + 1);
    if(ret == n - 1) ret += min(abs(r - l) + 1, abs(u - d) + 1);
    ans = min(ans, ret);
    r = 0, l = 2e9, d = 2e9, u = 0;
    for(int i = 1; i <= n - 1; i++)
    {
        LL x = b[i].x, y = b[i].y;
        l = min(l, x); r = max(r, x);
        d = min(y, d); u = max(u, y);
    }  
    ret = (abs(r - l) + 1) * (abs(u - d) + 1);
    if(ret == n - 1) ret += min(abs(r - l) + 1, abs(u - d) + 1);
    ans = min(ans, ret);
    r = 0, l = 2e9, d = 2e9, u = 0;
    for(int i = 2; i <= n; i++)
    {
        LL x = b[i].x, y = b[i].y;
        l = min(l, x); r = max(r, x);
        d = min(y, d); u = max(u, y);
    }  
    ret = (abs(r - l) + 1) * (abs(u - d) + 1);
    if(ret == n - 1) ret += min(abs(r - l) + 1, abs(u - d) + 1);
    ans = min(ans, ret);    
    return ans;
}
 
void solve() 
{
    cin >> n;;
 
    for(int i = 1; i <= n; i++) 
    {
        cin >> a[i].x >> a[i].y;
        b[i].x = a[i].x;
        b[i].y = a[i].y;
    }
    if(n == 1)
    {
        cout << 1 << endl;
        return;
    }
    sort(a + 1, a + 1 + n, cmp1);
    sort(b + 1, b + 1 + n, cmp2);
    cout << calc() << endl;
}
 
int main()
{
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int T;
	cin >> T;
	while(T--)
	{
        solve();
	}
	return 0;
}
posted @ 2025-06-22 20:07  hky2023  阅读(9)  评论(0)    收藏  举报