1. 程式人生 > >洛谷P2054 [AHOI2005]洗牌(擴展歐幾裏德)

洛谷P2054 [AHOI2005]洗牌(擴展歐幾裏德)

n+1 line spl .html swa 觀察 推出 exgcd fine

洛谷題目傳送門

來個正常的有證明的題解

我們不好來表示某時刻某一個位置是哪一張牌,但我們可以表示某時刻某一張牌在哪個位置。

設數列\(\{a_{i_j}\}\)表示\(i\)號牌經過\(j\)次洗牌後的位置,我們試著來遞推一下

首先,如果此刻牌在上面一疊,顯然\(a_{i_{j+1}}=2a_{i_j}\)

接著,如果這張牌在下面一疊,那麽\(a_{i_{j+1}}=2(a_{i_j}-\frac n2)-1=2a_{i_j}-(n+1)\),應該也很好推出來

寫在一起,觀察一下

\[a_{i_{j+1}}=\begin{cases}2a_{i_j}\qquad\qquad\ ,a_{i_j}\leq\frac n2\\2a_{i_j}-(n+1),a_{i_j}>\frac n2\end{cases}\]

誒,兩個式子都有一個系數\(2\)呢!那我們可不可以把它看成模\(n+1\)意義下的結果呢?

於是可以進一步得到\(a_{i_j}\equiv2^mi(\mod n+1)\)\(i\)就是\(a_{i_0}\)

題目已經知道了\(a_{i_j}\),來求\(i\),不就是一個線性同余不定方程麽?exgcd搞一下就好啦!因為\(\gcd(2^m,n+1)=1\),所以根本不用像青蛙的約會那樣麻煩。

看樓上大佬用異或寫swap?!第一次見的蒟蒻表示只能Orz。然後蒟蒻就把exgcd這個函數成功壓縮到了一行。。。。。。

#include<cstdio>
#define LL long long
LL n,m,l,x=1,y; LL qpow(LL b,LL k){//快速冪求2^m LL a=1; while(k){ if(k&1)a*=b,a%=n+1; b*=b,b%=n+1; k>>=1; } return a; } void exgcd(LL a,LL b){//一行exgcd233 if(b)exgcd(b,a%b),(y^=x^=y^=x)-=a/b*x; } int main(){ scanf("%lld%lld%lld",&n,&m,&l); exgcd(qpow(2
,m),n+1); printf("%lld\n",(l*x%(n+1)+n+1)%(n+1));//註意化成最小正整數 return 0; }

洛谷P2054 [AHOI2005]洗牌(擴展歐幾裏德)