【組合數學&&尤拉降冪】ACM-ICPC 2018 焦作賽區網路預賽 G. Give Candies
阿新 • • 發佈:2018-12-13
Step1 Problem:
有 n 個人編號為 1, 2, 3, …, n,有 n 個糖果,按編號從小到大順序分發給它們,所到編號至少得獲得一個糖果,求有多少種分配方案。
資料範圍:
1<=T<=100, 1<=n<=10^100000.
Step2 Ideas:
n個糖果恰好分給 1 個小朋友的方案數:C(n-1, 0)
n個糖果恰好分給 2 個小朋友的方案數:C(n-1, 1)
n個糖果恰好分給 3 個小朋友的方案數:C(n-1, 2)
… … … … … … … … … … … … … … … … … …
… … … … … … … … … … … … … … … … … …
n個糖果恰好分給 n 個小朋友的方案數:C(n-1, n-1)
C(n-1, 0) + C(n-1, 1) + C(n-1, 2) + … + C(n-1, n-1) = 2^(n-1)
對於 n 個糖果恰好分給 i 個小朋友的方案數:等價於 n-i 個球是無標誌的,i 個盒子是有區別的,取 n-1 個球放進盒子,每個盒子允許多於一個球的方案數。
C(i+(n-i)-1, n-i) = C(n-1, n-i) = C(n-1, i-1).
由於 n 很大,我們需要尤拉降冪:A^B mod D = A^( B%phi(D) + phi(D) ) mod D.
Step3 Code:
#include<bits/stdc++.h> using namespace std; #define ll long long const int N = 1e6+5; char s[N]; ll get_phi(ll x) { ll ret = x; ll m = sqrt(x); if(m*m > x) m--; for(int i = 2; i <= m; i++) { if(x%i == 0) { ret = ret/i*(i-1); while(x%i == 0) { x /= i; } } } if(x != 1) ret = ret/x*(x-1); return ret; } ll Pow(ll x, ll n, ll MOD) { ll ans = 1; while(n) { if(n&1) ans *= x, ans %= MOD; x = x*x, x %= MOD; n >>= 1; } return ans; } int main() { ios::sync_with_stdio(false); int T; //scanf("%d", &T); cin >> T; ll MOD; while(T--) { cin >> s; MOD = 1e9+7; ll phi = get_phi(MOD); int len = strlen(s); ll ans = 0; for(int i = 0; i < len; i++) { ans = ans*10+s[i]-'0'; ans %= phi; } cout << Pow(2, ans+phi, MOD)*Pow(2, MOD-2, MOD)%MOD << endl; //printf("%lld\n", Pow(2, ans+phi, MOD)*Pow(2, MOD-2, MOD)%MOD); } return 0; }