51Nod1778 小Q的集合 【組合數】【Lucas定理】
題目分析:
題解好高深......
我給一個辣雞做法算了,題解真的看不懂。
註意到方差恒為$0$,那麽其實就是要我們求$\sum_{i=0}^{n}\binom{n}{i}(i^k-(n-i)^k)^2$。
轉換一下
$\sum_{i=0}^{n}\binom{n}{i}(i^k-(n-i)^k)^2$
$=2\sum_{i=0}^{n}\binom{n}{i}(i^{2k}-i^k(n-i)^k)$
註意到$i^{2k}$與$i^k(n-i)^k$在模$m$意義下都是一個周期為$m$的數列,那麽我們需要求出每隔$m$個的組合數的和,即:
$2\sum_{i=0}^{m-1}(\sum_{j=0}^{\frac{n-i}{m}}\binom{n}{i+j*m}(i^{2k}-i^k(n-i)^k))$
把焦點放到內部的求和裏面去,它是很簡單的一個式子,試著轉化它。首先我們可以根據Lucas定理分析出,對於外部的$i$,它的結果中一定有$ \binom{n\%m}{i} $。
剩下的是什麽?首先有不等式$i+j*m \leq n\%m + \left \lfloor \frac{n}{m} \right \rfloor$。在這裏我們毫無疑問地認為$i \leq n\%m$。否則對結果無影響。
我們接受$\left \lfloor \frac{n}{m} \right \rfloor$的所有影響,取滿它,取滿一排,它是$2$的次冪。
所以這個式子就等於$2\sum_{i=0}^{m-1}(\binom{n\%m}{i}*2^{\left \lfloor \frac{n}{m} \right \rfloor}(i^{2k}-i^k(n-i)^k))$
$\left \lfloor \frac{n}{m} \right \rfloor$很大,采用費馬定理優化。
這樣我們就可以解決它在$O(mlogk)$的時間內了。
註意,如果我們會線性求逆元以及線性篩,可以去掉log。
代碼:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 1048576; 5 6 int mod,nr,k,np; 7 char str[maxn]; 8 int str2[maxn]; 9 10 int c[maxn],rw[maxn]; 1112 void read(){ 13 scanf("%s",str); 14 scanf("%d%d",&k,&mod); 15 int len = strlen(str); 16 for(register int i=0;i<len;i++){ nr = nr*10+str[i]-‘0‘; nr %= mod; } 17 for(register int i=0,num=0;i<len;i++){ 18 np = np*10+str[i]-‘0‘; str2[i] = np/mod; np %= mod; 19 } np = 0; 20 for(register int i=0;i<len;i++){ 21 np = np*10+str2[i]; np %= (mod-1); 22 } 23 } 24 25 int fast_pow(int now,int pw){ 26 int ans = 1,dd = now,base = 1; 27 while(base <= pw){ 28 if(base & pw){ans = (1ll*ans*dd)%mod;} 29 dd = (1ll*dd*dd)%mod; 30 base<<=1; 31 } 32 return ans; 33 } 34 35 int prime[maxn/8],flag[maxn],num; 36 void get_prime(int N){ 37 rw[1] = 1; flag[1] = 1; 38 for(int i=2;i<=N;i++){ 39 if(!flag[i]){prime[++num]=i;rw[i]=fast_pow(i,k);} 40 for(int j=1;j<=num&&i*prime[j]<=N;j++){ 41 flag[i*prime[j]] = 1; 42 rw[i*prime[j]] = (1ll*rw[i]*rw[prime[j]])%mod; 43 if(i%prime[j] == 0) break; 44 } 45 } 46 } 47 48 void init(){ 49 get_prime(nr); 50 np = fast_pow(2,np+1); c[0] = 1; 51 for(register int i=1;i<=nr;i++){ 52 c[i] = (1ll*c[i-1]*(nr-i+1))%mod; 53 c[i] = (1ll*c[i]*fast_pow(i,mod-2))%mod; 54 } 55 } 56 57 void work(){ 58 int ans = 0; 59 for(register int i=0;i<mod;i++){ 60 if(i > nr) break; 61 int hh = rw[i]; 62 int pp = ((1ll*hh*hh)%mod) - (1ll*hh*rw[nr-i])%mod; 63 if(pp < 0) pp += mod; 64 pp = (1ll*pp*c[i])%mod; 65 ans += pp; if(ans >= mod) ans -= mod; 66 } 67 ans += mod; if(ans >= mod) ans -=mod; 68 ans = (1ll*np*ans)%mod; 69 printf("%d",ans); 70 } 71 72 int main(){ 73 read(); 74 init(); 75 work(); 76 return 0; 77 }
51Nod1778 小Q的集合 【組合數】【Lucas定理】