luogu_P2054 bzoj 1965 洗牌 【题解】 快速幂 快速乘

题目链接:

  Luogu:https://www.luogu.org/problem/P2054

  bzoj:https://www.lydsy.com/JudgeOnline/problem.php?id=1965

找到规律:

  上一次在x位置,下一次就会在 x*2%(n+1) 位置

那么就是要求:

  x * (2^m) = L(mod n+1)

第一反应exgcd,但是突然感觉有点不太优秀。

因为n是偶数(题目说了)

所以2和n+1为互质

所以设 z *  2 =1(mod n+1)

  z就为2在mod n+1下的逆元

  z *  2 +(n+1)*y = 1

当 y=-1 时得出 z 最小为 n/2+1

所以 x=(n/2+1)^ m *L (mod n+1)

用一个快速幂和一个快速乘就可以切了。

不用快速乘中间会爆成负数。

代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll maxn=1e10+10;
ll n,m,l;
inline ll qm(ll x,ll y){
    ll mod=(n+1),ans=0;
    x%=mod;
    while(y){
        if(y&1) ans=(ans+x)%mod;
        x=(x+x)%mod;
        y>>=1;
    }
    return ans%mod;
}
inline ll qp(ll x,ll y){
    ll mod=(n+1),ans=1;
    x%=mod;
    while(y){
        if(y&1) ans=qm(ans,x)%mod;
        x=qm(x,x)%mod;
        y>>=1;
    }
    return ans%mod;
}
int main()
{
    scanf("%lld%lld%lld",&n,&m,&l);
    ll ans=qp(n/2+1,m);
    ans=qm(ans,l);
    printf("%lld\n",ans);
    //system("pause");
    return 0;
}

 

posted @ 2019-09-01 16:05  ChrisKKK  阅读(108)  评论(0编辑  收藏  举报