[2020HDU多校第七場][HDU 6847][D. Decision]
賽後聽說題解是環套樹上倍增表示一臉懵逼...又是被學弟們爆踩的一天_(:з」∠)_
題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=6847
題目大意:\(a,c,m,t\)為給定常數,\(V_1,V_2\)為從區間\([0,t]\)內等概率生成的兩個整數,令\(X_0=V_1+V_2, X_{n+1}=aX_n+c \mod m\),求\(X_{|V_1-V_2|}\)為偶數的概率
題解:將題目轉換為列舉\(V_1,V_2\)的所有取值,求\(X_{|V_1-V_2|}\)為偶數的方案數。考慮令\(f_0=V_1+V_2, f_{n+1}=af_n+c\),即數列不取模時的值。可以通過高中學過的數列知識計算得出\(f_n+\frac{c}{a-1}=a^n(f_0+\frac{c}{a-1})\),移項得到\(f_n =a^nf_0+c\cdot \frac{a^n-1}{a-1}=a^nf_0+c\sum_{i=0}^{n-1}a^i\)。
列舉\(|V_1-V_2|\)的值\(d\),要求的就是\(X_d = f_d \bmod m\)為偶數的方案數。令\(p_n=a^n, s_n=\sum_{i=0}^{n-1}a^i\),則\(X_d \equiv (V_1+V_2)p_d + cs_d \mod m\)。由於此時\(d\)已經固定,所以式子中的\(p_d\)與\(cs_d\)可以看作兩個常數\(c_1,c_2\),同時我們不妨設\(V_1 \ge V_2\),則有\(V_1=V_2+d,X_d \equiv (V_2+d+V_2)c_1 + c_2 \mod m\),化簡得到\(X_d \equiv 2c_1V_2 + c_1d+c_2 \mod m\),是一個\(kx+b\)的形式。
現在問題就轉化成了,已知整數\(x \in [0,t-d]\)(\(V_1=x+d\)要在\([0,t]\)內),求\(kx+b \bmod m\)為偶數的方案數。注意到我們之前求出的\(k=2c_1\)是一個偶數,所以在不考慮取模的情況下,\(kx+b\)的奇偶性是確定的。也就是說,如果\(m\)為偶數,\(kx+b \bmod m\)的奇偶性也是確定的,故我們只需要考慮\(m\)為奇數的情況。
當\(m\)為奇數時,可以通過觀察發現,若一個整數\(y\)對\(2m\)取模的值在\([m,2m-1]\)範圍內,即\(\lfloor \frac{y}{m}\rfloor\)為奇數,則\(y \bmod m\)與\(y\)的奇偶性恰好相反,故我們只需要計算出\(kx+b \bmod m\)與\(kx+b\)的奇偶性相反的次數即可。由於當\(\lfloor \frac{kx+b}{m}\rfloor\)為奇數時滿足這個條件,相當於我們只要求\(\lfloor \frac{kx+b}{m}\rfloor \bmod 2 = 1\)的次數,即\(x\)取遍\([0,t-d]\)時\(\lfloor \frac{kx+b}{m}\rfloor \bmod 2\)的和。而\(a \bmod b = a-\lfloor \frac{a}{b} \rfloor b\),所以我們要求的就是\(\sum_{x=0}^{t-d} \lfloor \frac{kx+b}{m}\rfloor -2\lfloor \frac{kx+b}{2m}\rfloor\)。發現減號前後的兩個式子都是\(\sum_{i=0}^{n} \lfloor \frac{ai+b}{c} \rfloor \)的形式,故可以使用類歐幾里得演算法求解,總時間複雜度為\(O(t \log t)\)。
#include<bits/stdc++.h> using namespace std; #define N 1000010 #define LL long long int T,t,a,c,m,p[N],s[N]; LL f(LL a,LL b,LL c,LL n) { LL m=(a*n+b)/c; if(!a || !m)return 0; if(a>=c || b>=c)return n*(n+1)/2*(a/c)+(b/c)*(n+1)+f(a%c,b%c,c,n); return n*m-f(c,c-b-1,a,m-1); } void init() { scanf("%d%d%d%d",&t,&a,&c,&m); p[0]=1; for(int i=1;i<N;i++){ p[i]=1ll*p[i-1]*a%m; s[i]=(s[i-1]+p[i-1])%m; } LL x=0,y=1ll*(t+1)*(t+1); for(int d=0;d<=t;d++){ int res=0,k=2ll*p[d],b=(1ll*c*s[d]+1ll*d*p[d])%m; if(m&1)res=f(k,b,m,t-d)-2ll*f(k,b,2*m,t-d); if(b&1)res=t-d+1-res; if(d)res*=2; x+=res; } x=y-x; LL d=__gcd(x,y); x/=d,y/=d; printf("%lld/%lld\n",x,y); } int main() { scanf("%d",&T); while(T--)init(); }View Code
由於一開始做這題的時候把題目要求的奇偶看反了,所以程式碼看上去可能有些奇怪_(:з」∠)_
值得注意的是在求\(k\)的值時不能對\(m\)取模,否則可能會導致\(k\)為奇數進而性質失效