OTZ Po姐姐
題目的意思是求C(n, m1) * C(n-m1, m2) * C(n-m1-m2, m2)….(mod P)
感覺是小學數學。。
化簡一下就是 n! /
但是mod的數不一定是質數,不能用費馬小定理。
我們可以對於每個質數塊
然後用中國剩餘定理合併
考慮一個較小的質數
此時
然後用指數相加或相減,ai相乘,除法就求逆元
現在的問題是如何處理n過大的問題
我們考慮一個數n!
舉個栗子
19!=1*2*3*4*5*6*7*8*9*10*11*12*13*14*15*16*17*18*19
然後mod 9
然後把和3有關的東西提出來
變成
19! = 1*2*4*5*7*8*10*11*13*14*16*17*19 *
有一些是mod 9同餘的
1*2*4*5*7*8=10*11*13*14*16*17(mod 9)
所以可以按照
至於6!遞歸處理
乘法的時候忘記mod掛long long好幾次=-=。。
#include
#define maxn 100010
using namespace std;
typedef long long ll;
ll P, sum;
int n, m, w[10];
int p[maxn], num[maxn], p_a[maxn], cnt;
void FJ(ll now){
for(int i = 2; i * i <= now; i ++){
if(now % i == 0){
cnt ++;
num[cnt] = 0;
p_a[cnt] = 1;
p[cnt] = i;
while(now % i == 0){
p_a[cnt] *= i;
now /= i;
num[cnt] ++;
}
}
}
if(now != 1){
cnt ++;
num[cnt] = 1;
p_a[cnt] = p[cnt] = now;
}
//for(int i = 1; i <= cnt; i ++)cout << p[i] << ' ' << p_a[i] << ' ' << num[i] << endl;
}
ll power_mod(ll a, ll b, ll mod){
ll ans = 1;
a %= mod;
while(b){
if(b & 1)ans = ans * a % mod;
b >>= 1;
a = a * a % mod;
}return ans % mod;
}
//ax + by = 1;
void Exgcd(ll a, ll b, ll& d, ll& x, ll& y){
if(!b){d = a; x = 1; y = 0; return;}
Exgcd(b, a%b, d, y, x);
y -= x * (a / b);
}
ll d, x, y;
ll inv(ll a, ll b){
Exgcd(a, b, d, x, y);
return (x + b) % b;
}
ll ans[maxn], M, now;
int pos;
typedef pair Point;
Point operator * (const Point& a, const Point& b){
return make_pair(a.first * b.first % now, a.second + b.second);
}
Point operator / (const Point& a, const Point& b){
return make_pair(a.first * inv(b.first, now) % now, a.second - b.second);
}
Point Fac(ll x){
Point ret = make_pair(1ll, x / p[pos]);
for(ll i = 1; i < p_a[pos]; i ++)
if(i % p[pos])ret.first = ret.first * i % p_a[pos];
ret.first = power_mod(ret.first, x / p_a[pos], p_a[pos]);
for(ll i = x - x % p_a[pos] + 1; i <= x; i ++)
if(i % p[pos])ret.first = ret.first * i % p_a[pos];
if(ret.second)ret = ret * Fac(ret.second);
return ret;
}
void work(int Id){
now = p_a[Id], pos = Id;
Point o = Fac(n);
for(int i = 1; i <= m; i ++)
o = o / Fac(w[i]);
ans[Id] = o.first * power_mod(p[Id], o.second, now) % p_a[Id];
}
ll CRT(){
ll ret = 0, w;
for(int i = 1; i <= cnt; i ++){
now = p_a[i], w = M / now;
ret = (ret + inv(w, now) * w % M * ans[i] % M) % M;
}
ret %= M;
if(ret < 0)ret += M;
return ret;
}
int main(){
cin >> P >> n >> m;
M = P;
sum = 0;
for(int i = 1; i <= m; i ++)
cin >> w[i], sum += w[i];
if(sum > n){puts("Impossible");return 0;}
FJ(P);w[++ m] = n - sum;
for(int i = 1; i <= cnt; i ++)work(i);
cout << CRT() << endl;
return 0;
}