【状态】(数论)
【状态】(数论)
一般数字本身的范围很小->直接以数字本身作为状态
类线性dp去转移
Small Operations
https://codeforces.com/contest/2114/problem/F
思路
一个是乘一个是除->尝试缩短为1个操作
->x和y都除到1找最短路线
->如何找最短路线?线性dp因数
代码
bool cmpll(ll a,ll b){return a<b;}
const ll INF=1e10;
//把x和y都变成1:考虑乘法/除法->考虑乘法
//问题转化为一个数化为x个比k小的数相乘 求x最小值
ll x,y,k;
vector<ll> get_divisors(ll n){
vector<ll> res;
for(ll i=1;i<=n/i;i++){
if(n%i==0){
res.push_back(i);
//注意这里要判断 如果两个相同就只加一个
if(i!=n/i) res.push_back(n/i);
}
}
sort(res.begin(),res.end(),cmpll);
return res;
}
ll get_ans(ll num){
if(num==1) return 0;//已经是最终状态了
vector<ll> divs=get_divisors(num);
int l=divs.size();
//对因数进行dp:dp[i]表示从数字divs[i]变到1的最少操作次数
/*【状态转移】
大数可以被小数整除 divs[i] % divs[j] == 0
可通过一次操作从divs[i]变成divs[j]
*/
//特殊情况:divs[j]从大到小遍历:若divs[i]/divs[j]>k->后面的也一定会>k
vector<ll> dp(l+1,INF);
dp[0]=0;
//divs[0]都是1 是最终状态
for(int i=1;i<l;i++){
for(int j=i-1;j>=0;j--){
if(divs[i]/divs[j]>k) break;
if(divs[i]%divs[j]==0){
dp[i]=min(dp[i],dp[j]+1);
}
}
}
//divs[l-1] 最后一个数都是num本身
if(dp[l-1]==INF) return -1;
else return dp[l-1];
}
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
void solve(){
cin>>x>>y>>k;
ll g=gcd(x,y);
x=x/g;
y=y/g;
ll ans1=get_ans(x);
ll ans2=get_ans(y);
if(ans1==-1 || ans2==-1) cout<<"-1"<<endl;
else cout<<(ans1+ans2)<<endl;
}
Gellyfish and Flaming Peony
https://codeforces.com/contest/2116/problem/C
思路
首先特判数组中只有1个数->答案为0
统计公共gcd:若数组中已经有数是公共gcd了->直接转化
否则找1->先除公共gcd 接下来一定可以造出1
设状态:一个数通过操作到达1的最小次数->bfs去进行状态转移
代码
const int N=5010;
int n;
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
void solve(){
cin>>n;
vector<int> a(n+1,0);
for(int i=1;i<=n;i++) cin>>a[i];
int g=a[1];
if(n==1){
cout<<0<<endl;
return;
}
for(int i=1;i<=n;i++){
g=gcd(g,a[i]);
}
int cnt=0;
for(int i=1;i<=n;i++){
if(a[i]==g){
cnt++;
}
a[i]/=g;
}
if(cnt){
cout<<n-cnt<<endl;
return;
}
//找一个数通过操作到达1的最小次数 然后统计整个数组的最小次数->bfs
vector<int> dp(N,-1);//对数本身(<=5000)往后找
queue<int> q;
for(int i=1;i<=n;i++){
if(dp[a[i]]==-1){
dp[a[i]]=0;//有的数
q.push(a[i]);
}
}
int ans=INF_INT;
while(q.size()){
int t=q.front();
q.pop();
if(t==1){
ans=dp[t];
break;
}
for(int i=1;i<=n;i++){
int p=gcd(t,a[i]);
if(dp[p]==-1){
dp[p]=dp[t]+1;
q.push(p);
}
}
}
if(ans==INF_INT) ans=0;
cout<<ans+n-1<<endl;
}

浙公网安备 33010602011771号