【BZOJ1965/Ahoi2005】SHUFFLE 洗牌

题目:BZOJ1965

解析:

  法一:找规律
  手玩样例可以发现原位置为 p p p的数经过 m m m次洗牌后位置变为: p ∗ 2 m m o d ( n − 1 ) p*2^mmod(n-1) p2mmod(n1)
  法二:稍微严谨的数学证明
  如果当前位置为 p p p变化一次后到哪个位置,存在两种情况:
  1. p ≤ n 2 p\le\frac{n}{2} p2n
  易知变到第 2 p 2p 2p个位置。
  2. n 2 &lt; p ≤ n \frac{n}{2}&lt;p\le n 2n<pn
  易知变到第 ( p − n / 2 ) ∗ 2 − 1 = 2 p − n − 1 ( p − n / 2 ) ∗ 2 − 1 = 2 p − ( n + 1 ) (p−n/2)∗2−1=2p−n−1(p−n/2)∗2−1=2p−(n+1) (pn/2)21=2pn1(pn/2)21=2p(n+1)个位置。
  前面显然有 2 p ≤ n 2p\le n 2pn
  后面有 p ≥ n / 2 + 1 = &gt; 2 p ≥ n + 2 = &gt; 2 p &gt; n + 1 p\ge n/2+1=&gt;2p\ge n+2=&gt;2p &gt; n+1 pn/2+1=>2pn+2=>2p>n+1
  所以我们可以认为每次操作之后都由 p p p位置变成了 2 l m o d ( n + 1 ) 2lmod(n+1) 2lmod(n+1)位置。
  所以原问题变为求解 x ∗ 2 m ≡ L ( m o d ( n − 1 ) ) x*2^m\equiv L(mod(n-1)) x2mL(mod(n1)),转换一下得到: x ≡ L / 2 m ( m o d ( n − 1 ) ) x\equiv L/2^m(mod(n-1)) xL/2m(mod(n1))
  注意到 2 m 2^m 2m n + 1 n+1 n+1是互质的。所以直接用扩欧求逆元再用快速幂求解即可。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;

int n,m,l,mod,x,y;

inline int mul(int a,int b){int ans=0;while(b){if(b&1)ans=(ans+a)%mod;b>>=1,a=(a+a)%mod;}return ans;}
inline int ksm(int a,int b){int ans=1;while(b){if(b&1)ans=mul(ans,a);b>>=1,a=mul(a,a);}return ans;}
inline void exgcd(int a,int b)
{
	if(!b) x=1,y=0;
	else
	{
	  exgcd(b,a%b);
	  int t=x;
	  x=y,y=t-a/b*x;
	}
}

signed main()
{
	cin>>n>>m>>l,mod=n+1;
	exgcd(ksm(2,m),mod);
	x=(x%mod+mod)%mod;  //若不转成最小正整数解可能是负数快速乘会T!
	cout<<mul(l,x)<<"\n";
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值