[高精度]SCOI2019:跳跃游戏

传送门

打表找规律可以发现答案是一段一段连续的区间
用类似于汉诺塔的方法可以推出小球i的通项公式
具体的,第一个球的答案为不为3的倍数的数
第二个球的答案为为3的倍数的数但不为9的倍数的数
第二个球的答案为为9的倍数的数但不为27的倍数的数
类推下去,高精度算个答案就完了

Code:

#include
#define ll long long
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
struct gj{
	int n;
	int a[505];
	gj(){n=0;memset(a,0,sizeof(a));}
	inline gj operator + (const gj x)const{
		gj res;res.n=max(n,x.n);
		for(int i=1;i<=res.n;i++){
			res.a[i]+=x.a[i]+a[i];
			if(res.a[i]>=10) res.a[i]-=10,res.a[i+1]++;
		}
		if(res.a[res.n+1]) res.n++;
		return res;
	}
	inline gj operator / (const ll &b)const{
		ll ans=0;gj res;res.n=n;
		for(int i=res.n;i;i--){
			ans=ans*10+a[i];
			if(ans>=b) res.a[i]=ans/b,ans-=(ans/b)*b;
		}
		while(res.n && !res.a[res.n]) res.n--;
		return res;
	}
	inline int operator %(const ll &b){
		ll res=0;
		for(int i=n;i;i--){
			res=(res<<1)+(res<<3)+a[i];
			if(res>=b) res-=(res/b)*b;
		}
		return res;
	}
	inline void read(){
		char ch=getchar();
		while(!isdigit(ch)) ch=getchar();
		while(isdigit(ch)) a[++n]=ch^48,ch=getchar();
		reverse(a+1,a+n+1);
	}
}l;
ll f[31],mod;
int main(){
	int n=read(),m=read(),k=read(),q=read();
	f[1]=1,f[2]=2,mod=3*n-3;
	for(int i=3;i<=30;i++) f[i]=f[i-1]*3ll;
	l.n=1;l.a[1]=1;
	while(q--){
		gj p;p.read();
		ll res=p%mod;
		p=p/mod,p=p+p,p=p+p;
		if(res>0) p=p+l;
		if(res>n-1) p=p+l;
		if(res>n-1+k-1) p=p+l;
		if(res>n-1+k-1+n-1) p=p+l;
		for(int i=1;i<=29;i++) if(p%f[i+1]!=0) {cout<<i<<'\n';break;}
	}
	return 0;
} 

你可能感兴趣的:(高精度)