2021南京icpc J
題意:
給出兩個整數 a , b a,b a,b,每次可以選擇如下一個操作進行:
(1)把 a , b a,b a,b都+1
(2)把 a , b a,b a,b都-1
(3)把 a , b a,b a,b都除以一個他們的公共質因子
問最小次數,使得 a , b a,b a,b至少存在一個等于1
Solution:
不妨令 a ≤ b a\leq b a≤b
假設某個時候,我們沒有質因子可以除,那么我們需要利用 + 1 , ? 1 +1,-1 +1,?1移動到一個有公共質因子的地方,然后再操作,如果到某個地方,兩數存在有公共質因子,顯然,他們的差 b ? a b-a b?a一定是這個公共質因子的倍數,于是,他們的公共質因子一定是 b ? a b-a b?a的任意一個公共質因子,那么唯一分解 b ? a b-a b?a,對于每個 a , b a,b a,b,可以有這樣的操作,一直-1到某個有公共質因子的地方,或者一直-1
到1,顯然第二個的次數是 a ? 1 a-1 a?1,而第一種,我們需要枚舉 b ? a b-a b?a的質因子 p p p,此時有兩種決策,即把 a a a移至最接近的兩個 p p p的倍數,即 p × ? a p ? p\times\lfloor\frac{a}{p}\rfloor p×?pa??和 p × ? a p ? p\times \lceil\frac{a}{p}\rceil p×?pa??,然后除 p p p,此時操作次數為 ∣ r e s ? a ∣ + 1 |res-a|+1 ∣res?a∣+1, r e s res res是 a a a移動到的數值,每次枚舉決策,記憶化搜索即可
訓練的時候一直調不出來,原來是有一個函數寫反參數,向上取整腦子短路寫錯了。。
#include<bits/stdc++.h> using namespace std;using ll=long long; #define div ttttttmp const int N=200005,inf=0x3fffffff; const long long INF=0x3f3f3f3f3f3f,mod=998244353;int prime[N],cnt; bool isprime[N];void make_prime() {memset(isprime,true,sizeof(isprime));for(int i=2;i<=100000;i++){if(isprime[i]) prime[++cnt]=i;for(int j=1;j<=cnt&&i*prime[j]<=100000;j++){isprime[i*prime[j]]=false;if(i%prime[j]==0) break;}} }ll ceil(ll a,ll b){return a%b?a/b+1:a/b;}vector<ll>div; map<pair<ll,ll>,ll>map1;ll dfs(ll x,ll del) {if(x==1) return 0;if(map1.count({x,del})) return map1[{x,del}];ll min1=x-1;for(int i:div){if(del%i) continue;if(i*(x/i)) min1=min(min1,dfs(x/i,del/i)+x-(i*(x/i))+1);if(i*ceil(x,i)) min1=min(min1,dfs(ceil(x,i),del/i)+i*ceil(x,i)-x+1);}return map1[{x,del}]=min1; }void work() {ll a,b;scanf("%lld%lld",&a,&b);if(a>b) swap(a,b);map1.clear(); div.clear();ll tmp=b-a;for(int i=1;i<=cnt&&tmp>1;i++){if(tmp%prime[i]==0) div.push_back(prime[i]);while(tmp%prime[i]==0) tmp/=prime[i];}if(tmp>1) div.push_back(tmp);printf("%lld\n",dfs(a,b-a)); }int main() {make_prime();int t; cin>>t;while(t--) work();return 0; }總結
以上是生活随笔為你收集整理的2021南京icpc J的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CPU指令集是什么东西,以及指令集的架构
- 下一篇: 一夜暴涨12%市值突破7000亿美元,英