Historical Maths(二分判断进制)
题目描述
2 2 0 1 2 3 1 0 0
Output
4
题目大意:就是给你一组数组A,数组B,数组C。然后问你是否有一个k,就是使得k进制下A数组变成10进制数a,和k进制下B数组变成10进制数b,和k进制下的C数组变成的数c
使得a*b==c,求这个k
题目大意
需要观察出进制与 A * B 和 C 的大小之间具有单调性,如果进制较小的话,那么进位自然就会变多,从而使得位数边长,整体数字就会变大,反之亦然,所以据此,可以直接二分答案,用一个 check 进行检查,需要注意的是答案会爆 long long,所以整体用 __int128 进行计算即可,二分的下限设置为所有数字的最大值 + 1,上限设置为 1e20
首先这个题的下限要设成所有数的最大值+1,例如10进制下最大值是9。或者求完之后再判断一下
这个是用二分的位数判断的,如果位数大的话,就增大进制,小的话就减小进制,如果相等的话就从大到小看看第一个不同的数,如果大的话就增大进制,变小要减小进制
#include<iostream> #include<algorithm> #include<queue> using namespace std; typedef __int128 ll; const int maxn=2e6+100; const int N=1e3+100; inline __int128 read() { __int128 x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x*f; } inline void write(__int128 x) { if(x<0) { putchar('-'); x=-x; } if(x>9) write(x/10); putchar(x%10+'0'); } ll x[N]; ll y[N]; ll z[N]; ll res[maxn]; ll ans[maxn]; int n,m,k; ll ma=0; int judge(ll mid){ ll yu=0; int pos; for(pos=0;;pos++){ if((ans[pos]+yu)==0&&pos>=n+m-2){ break; } res[pos]=(ans[pos]+yu)%mid; yu=(ans[pos]+yu)/mid; //cout<<res[pos]<<" "<<yu<<endl; } // cout<<mid<<" "<<pos<<endl; if(pos==k){ for(int i=pos-1;i>=0;i--){//一定要从大到小 // cout<<res[i]<<endl; if(z[i]<res[i]){ return pos+2; } else if(z[i]>res[i]){ return pos-2; } } return -1; } return pos; } int main(){ cin>>n; for(int i=n-1;i>=0;i--){ x[i]=read(); //scanf("%lld",&x[i]); ma=max(ma,x[i]); } cin>>m; for(int i=m-1;i>=0;i--){ y[i]=read(); //scanf("%lld",&y[i]); ma=max(ma,y[i]); } cin>>k; for(int i=k-1;i>=0;i--){ z[i]=read(); //scanf("%lld",&z[i]); ma=max(ma,z[i]); } for(int i=0;i<=n-1;i++){ for(int j=0;j<=m-1;j++){ ans[i+j]+=1ll*(x[i]*y[j]); } } //judge(4); /* for(int i=0;i<=n+m-2;i++){ cout<<ans[i]<<endl; } //*/ ll l=2,r=1e22,ans; while(r>=l){ ll mid=(l+r)/2; if(judge(mid)==-1){ if(mid<=ma){ cout<<"impossible"<<"\n"; return 0; } write(mid); //cout<<mid<<"\n"; return 0; } if(judge(mid)<k){ r=mid-1; } else{ l=mid+1; } } cout<<"impossible"<<"\n"; }