NOIp训练 [SCOI2019]跳跃游戏(高精度)

传送门
吐槽:看到Owenowl说可以用两个long long代替高精???不会啊我tcl。
题意:
有m个小红球,n个空岛。其中第一个、最后一个空岛以及中间的第k个空岛是固定的(1< k< n)是固定的,其余空岛是悬浮的。一开始所有小红球都在第一个空岛,你的目标是把他们都移动到最后一个空岛,并且使用的步数尽量小。
每回合你可以移动一个小红球到它左边或者右边的那个平台,但是有一些限制:
1、移动的小红球必须是移动前它所在的平台上编号最小的
2、移动的小红球必须是移动后它所在的平台上编号最小的。
3、如果一个小红球移动到了一个浮动平台上,那下一回合必须将这个小红球移走,否则它就会掉下去。
有q个询问,每次给出一个时刻,你需要回答在最优方案中,这个时刻正在跳跃的是哪个小红球。
保证答案小于30,n≤10^8,m≤1000,q≤5000
保证询问给出的时刻小于等于最优方案数。
思路:
考虑到一个很显然的式子 f i = 3 f i − 1 + n − 1 f_i=3f_{i-1}+n-1 fi=3fi1+n1(汉诺塔问题变形)
然后我考场上就跑去高精暴力递推出所有的 f i f_i fi每次询问搜索然后卡常了(结果最后得分跟没写高精度一样23333)
考虑这个 f f f数列的通项公式: f i = ( n − 1 ) ( 3 i − 1 ) f_i=(n-1)(3^i-1) fi=(n1)(3i1)
观察到假如没有浮动平台方案数是2(3^i-1),这个时候就是普通的汉诺塔问题。
假设现在询问的时间点是 t t t
那么先把 t t t变成 t / ( n − 1 ) ∗ 2 t/(n-1)*2 t/(n1)2转化成普通汉诺塔问题,并根据模数让小球再走 0 / 1 / 2 0/1/2 0/1/2步让其走到最右边的柱子上。
这个时候就可以让 t t t一直模 3 3 3啦,模到有余数说明就是这个数。
注意读入时间点的时候是高精。。。
代码:

#include
#define ri register int
#define fi first
#define se second
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
	static char buf[rlen],*ib,*ob;
	(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
	return ib==ob?-1:*ib++;
}
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
typedef long long ll;
struct num{
	vector<int>a;
	inline void read(){
		a.clear();
		char ch=gc();
		while(!isdigit(ch))ch=gc();
		while(isdigit(ch))a.push_back(ch^48),ch=gc();
		reverse(a.begin(),a.end());
	}
	inline int deg()const{return a.size()-1;}
	inline num operator+(const num&b){
		int m=b.deg(),n;
		if(m>deg())a.resize(m+1);
		n=deg();
		for(ri i=0;i<=m;++i)a[i]+=b.a[i];
		for(ri i=0;i<=n;++i){
			if(a[i]<10)continue;
			if(i==n)++n,a.push_back(a[i]/10),a[i]%=10;
		}
		return *this;
	}
	inline void operator=(const int&b){
		a.clear();
		int t=b;
		while(t)a.push_back(t%10),t/=10;
	}
	inline pair<num,ll> operator/(const int&b){
		int n=deg();
		num ret;
		ll t=0;
		bool f=0;
		for(ri i=n;~i;--i){
			if(a[i]<b){
				if(!i){t=a[i];break;}
				a[i-1]+=a[i]*10;
				if(f)ret.a.push_back(0);
			}
			else{
				f=1;
				ret.a.push_back(a[i]/b);
				if(i)a[i-1]+=a[i]%b*10;
				else t=a[i]%b;
			}
		}
		if(!ret.a.size())ret.a.push_back(0);
		return reverse(ret.a.begin(),ret.a.end()),make_pair(ret,t);
	}
}A,add1,add2;
int n,m,k;
int main(){
	n=read(),m=read(),k=read();
	add1=1,add2=2;
	for(ri tt=read();tt;--tt){
		A.read();
		pair<num,ll>t=A/(n-1);
		A=t.fi+t.fi;
		if(t.se&&t.se<k)A=A+add1;
		if(t.se>=k)A=A+add2;
		int ans=1;
		while(1){
			t=A/3;
			A=t.fi;
			if(t.se)break;
			++ans;
		}
		cout<<ans<<'\n';
	}
	return 0;
}

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