2018.11.07 bzoj1965: [Ahoi2005]SHUFFLE 洗牌(快速幂+exgcd)

时间:2023-03-10 01:25:42
2018.11.07 bzoj1965: [Ahoi2005]SHUFFLE 洗牌(快速幂+exgcd)

传送门

发现自己的程序跑得好慢啊233.

管他的反正AC了


先手玩样例找了一波规律发现题目要求的就是a∗2m≡l(modn+1)a*2^m\equiv l \pmod {n+1}a∗2m≡l(modn+1)

然后脑补了一波sbsbsb数学证明。

假设当前牌aaa在第ppp个位置(为了方便假设在左半边,右半边的差不多)。

然后在这一次洗牌之后会有2∗(p−1)+1=2∗p−12*(p-1)+1=2*p-12∗(p−1)+1=2∗p−1张牌在它的前面。

于是它移到了第2∗p2*p2∗p个位置。

证毕。

然后为了防止爆longlonglong longlonglong我手写了一个快速乘估计就是这个地方慢了(都是借口明明是自己菜。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,m,l,a,b;
inline ll ksc(ll x,ll p,ll mod){ll ret=0;for(;p;p>>=1,x=(x+x)%mod)if(p&1)ret=(ret+x)%mod;return ret;}
inline ll ksm(ll x,ll p,ll mod){ll ret=1;for(;p;p>>=1,x=ksc(x,x,mod))if(p&1)ret=ksc(ret,x,mod);return ret;}
inline ll gcd(ll a,ll b){while(b){ll t=a;a=b,b=t%a;}return a;}
inline void exgcd(ll a,ll b,ll&x,ll&y){
	if(!b){x=1,y=0;return;}
	exgcd(b,a%b,x,y);
	ll tmp=x;
	x=y,y=tmp-a/b*y;
}
int main(){
	cin>>n>>m>>l,a=ksm(2ll,m,n+1),b=n+1;
	ll g=gcd(a,b),x,y;
	a/=g,b/=g,l/=g;
	exgcd(a,b,x,y);
	x=(ksc(x,l,b)+b)%b;
	cout<<x;
	return 0;
}