結果
問題 | No.117 組み合わせの数 |
ユーザー | btk |
提出日時 | 2015-06-11 14:12:30 |
言語 | C++11 (gcc 11.4.0) |
結果 |
RE
|
実行時間 | - |
コード長 | 2,010 bytes |
コンパイル時間 | 577 ms |
コンパイル使用メモリ | 64,092 KB |
実行使用メモリ | 11,008 KB |
最終ジャッジ日時 | 2024-07-06 15:35:43 |
合計ジャッジ時間 | 1,531 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge1 |
(要ログイン)
ソースコード
#include<iostream> #include<stdio.h> #include<vector> using namespace std; namespace mod{ typedef long long LL; typedef vector<LL> VLL; typedef vector<VLL> VVLL; const int MOD=(int)(1e9+7); // aとbの最大公約数 // O(log (a+b) ) LL gcd(LL a,LL b){ return (b==0)?a:gcd(b,a%b); } // aとbの最小公倍数 // O(log (a+b) ) LL lcm(LL a,LL b){ return (a*b)/gcd(a,b); } // a x + b y = gcd(a, b) // O(log (a+b) ) LL extgcd(LL a, LL b, LL &x, LL &y) { LL g = a; x = 1; y = 0; if (b != 0) g = extgcd(b, a % b, y, x), y -= (a / b) * x; return g; } // mを法とするaの逆元 // O(log a) LL invMod(LL a) { LL x, y; if (extgcd(a, MOD, x, y) == 1) return (x + MOD) % MOD; else return 0; // unsolvable } // iCjの組み合わせを全列挙してvectorに格納 // (0<=j<=i<=n) // O(n^2) VVLL init_comb(int n){ n++; VVLL res(n,VLL(n,0)); for(int i=0;i<n;i++)res[i][0]=1; for(int i=1;i<n;i++) for(int j=1;j<=i;j++) res[i][j]=(res[i-1][j]+res[i-1][j-1])%MOD; return res; } // 階乗 // O(n) LL fact[1000001]={0}; void init(){ for(int i=1;i<1000001;i++) fact[i]=(fact[i-1]*i)%MOD; } // 組み合わせnCk (mod MOD) // O(n) LL Comb(LL n,LL k){ LL u=fact[n]; LL d=(fact[k]*fact[n-k])%MOD; return (u*invMod(d))%MOD; } LL Parm(LL n,LL k){ LL u=fact[n]; LL d=(fact[n-k])%MOD; return (u*invMod(d))%MOD; } // 1~nの逆元を求める(mod MOD) VLL list_mod_inverse(LL n){ VLL inv(n + 1); inv[1] = 1; for (int i = 2; i <= n; ++i) inv[i] = inv[MOD % i] * (MOD - MOD / i) % MOD; return inv; } } int main(){ mod::init(); int T; cin>>T; while(T--){ string s; cin>>s; char c=s[0]; int i=2; mod::LL n=0; for(;s[i]!=',';i++){ n*=10; n+=(s[i]-'0'); } i++; int k=0; for(;s[i]!=')';i++){ k*=10; k+=(s[i]-'0'); } switch(c){ case 'P': cout<<mod::Parm(n,k)<<endl;break; case 'H': n=n+k-1; default: cout<<mod::Comb(n,k)<<endl;break; } } return 0; }