2021icpc南京 J. Xingqiu‘s Joke(数论)

题意:

,每组测试数据输入两相异整数a,b (1≤a,b≤1e9),每次进行如下三种操作之一,直至a,b中至少有一个为1,输出最小步数

①两数同时加一

②两数同时减一

③两数同除以它们的一个公共质因子

这题有一个很重要的信息

再1操作和2操作中,a-b是不会变的

而假设3操作中a,b同时除以g,那么a和b的差值也会除以g

也就是如果我们设c=a-b,每一次除g,相当于(\frac{a}{g},\frac{b}{g},\frac{c}{g})

当然,g必须是c的质因子

显然如果我们设a<b,上式可以简化为(\frac{a}{g},\frac{c}{g})

也就是我们要通过1,2,3操作,使得a变成1,而c会限制操作3

可以考虑将c分解质因数,通过分解出的质因数和12操作一起记忆化搜索

小优化:unorderedmap在多查询时会比map快很多,但如果想传入一个pair,需要自己写一个hash函数

代码如下:

#include <bits/stdc++.h>
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair<int,int>
#define et  cout<<'\n'
#define xx first
#define yy second
using namespace std;
template <typename _Tp>void input(_Tp &x){
    char ch(getchar());bool f(false);while(!isdigit(ch))f|=ch==45,ch=getchar();
    x=ch&15,ch=getchar();while(isdigit(ch))x=x*10+(ch&15),ch=getchar();
    if(f)x=-x;
}
template <typename _Tp,typename... Args>void input(_Tp &t,Args &...args){input(t);input(args...);}
const int N=1e6+10;
struct hash_pair{ 
    template <class T1, class T2> 
    size_t operator()(const pair<T1, T2>& p) const
    { 
        auto hash1=hash<T1>{}(p.first); 
        auto hash2=hash<T2>{}(p.second); 
        return hash1^hash2; 
    } 
}; 
vector<int> this_prime;
unordered_map<pll,int,hash_pair> mp;
signed main(){    
    function<void(int)> get=[&](int d){
        for(int i=2;i*i<=d;++i){
            if(d%i==0){
                this_prime.pb(i);
                while(d%i==0) d/=i;
            }
        }
        if(d>1) this_prime.pb(d);
    };
    function<int(int,int)> dfs=[&](int a,int d){
        pll now={a,d};
        if(a==1){
            return 0ll;
        }
        else if(mp[now]){
            return mp[now];
        }
        int res=a-1;
        for(auto v:this_prime){
            if(d%v==0){
                int x=dfs(a/v,d/v)+a%v;
                int y=dfs(a/v+1,d/v)+v-a%v;
                res=min({res,1+x,1+y});
            }
        }
        mp[now]=res;
        return res;
    };
    int T;
    cin>>T;
    while(T--){
        int a,b;
        input(a,b);
        mp.clear();
        this_prime.clear();
        if(a>b) swap(a,b);
        if(a==1){
            cout<<0<<'\n';
            continue;
        }
        else if(b-a==1){
            cout<<a-1<<'\n';
            continue;
        }
        else if(a==b){
            cout<<1<<'\n';
            continue;
        }
        get(b-a);
        cout<<dfs(a,b-a)<<'\n';
    }



}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值