T1
为了避免晚上种种事情导致写不成题解就先把T1写了,毕竟也是很值得写的。
我这道题凭着一个半感性半理性的想法意外的水到了80分……真的是很考人品啊【学竞赛啊,坠重要的就是人品!】
先看正解:
我们可以这样化:
T=(((s∗bk1+i1∗a)∗bk2+i2∗a)∗bk3+i3∗a)∗bk4+......
再化简一下:
T=s∗bk1+...+kn+i1∗a∗bk2+...+kn+...+in∗a∗bkn
所以我们可以在最外层枚举
k1+...+kn
,然后把剩余的值/a,开始递归,接着依次枚举
k2+...+kn,k3+...+kn,.....,kn
每次使它们的值尽量大,这样得到的加减次数就会尽量小了。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=1e9;
int s,t,a,b;
int mpow[30];
int solve(int x,int tmp)
{
if(x==0) return 0;
for(int i=tmp;i>=0;i--){
if(mpow[i]>x) continue;
for(int j=0;;j++){
if(j*mpow[i]<=x&&(j+1)*mpow[i]>x) {
int ret=solve(x-j*mpow[i],i);
if(ret==-1) return -1;
return ret+j;
}
}
}
}
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int ans=inf,cnt=0;
scanf("%d%d%d%d",&s,&t,&a,&b);
//T=s*b^(k1+....kn)+i1*a*b^(k2+....kn)+...+in*a*b^kn
mpow[0]=1;
for(int i=1;mpow[i-1]<=t;i++,cnt++) mpow[i]=mpow[i-1]*b;
cnt--;
for(int i=0;i<=cnt;i++){
if((t-s*mpow[i])%a==0){
int ret;
ret=solve((t-s*mpow[i])/a,i);
if(ret==-1) continue;
ans=min(ans,i+ret);
}
}
if(ans==inf) printf("-1");
else printf("%d",ans);
return 0;
}
我的那个诡异的方法是怎么回事晚上补
T3
易理解具有二分性质
易理解进行x轮操作,可以把小B的操作全部提到前面。
把每个数指向它应该在的位置,如果形成了一个环,那么环内交换的数一共只用“环内数字-1”
例:1 3 2 5 4