4338: BJOI2015 糖果
Time Limit: 2 Sec Memory Limit: 256 MBSubmit: 141 Solved: 66
[ Submit][ Status][ Discuss]
Description
Alice 正在教她的弟弟 Bob 学数学。
每天,Alice 画一个N行M 列的表格,要求 Bob在格子里填数。
Bob已经学会了自然数1到K的写法。因此他在每个格子里填1 ~ K之间的整数。
Alice 告诉 Bob,如果 Bob 填写完表格的 N*M 个数以后,每行的数从第 1 列到第 M
列单调不减,并且任意两行至少有一列的数不同,而且以前 Bob 没有填写过相同的表格,
那么Alice 就给Bob吃一颗糖果。
Bob想知道,如果每天填写一遍表格,最多能吃到多少颗糖果。
答案模P输出。
Input
第一行,四个整数依次是N, M, K, P。
Output
输出一行,一个整数,表示答案模P 后的结果。
Sample Input
【样例输入1】
1 3 3 10
【样例输入2】
2 2 2 10
1 3 3 10
【样例输入2】
2 2 2 10
Sample Output
【样例输出1】
0
【样例输出2】
6
0
【样例输出2】
6
HINT
【样例解释】
样例1。表格只有一行。每个格子可以填写1 ~ 3。有10种填写方法,依次为1 1 1,
1 1 2,1 1 3,1 2 2,1 2 3,1 3 3,2 2 2,2 2 3,2 3 3,3 3 3。
样例2。表格有两行。有6 种填写方法,依次为 1 1/1 2, 1 1/2 2, 1 2/1 1, 1 2/2
2, 2 2/1 1, 2 2/1 2。
【数据规模与约定】
100% 的数据中,1 ≤ N, M ≤ 10^5,1 ≤ P, K ≤ 2*10^9.
Source
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<bitset>
using namespace std;
const int maxn = 1E5 + 10;
typedef long long LL;
LL N,M,K,P,r1,a1,fac[maxn],inv[maxn];
int tot,pri[maxn];
bool not_pri[maxn];
void Extend_Gcd(LL a,LL &x,LL b,LL &y)
{
if (!b) {x = 1; y = 0; return;}
Extend_Gcd(b,y,a%b,x); y -= x*(a/b);
}
LL C(int n,int m,LL g)
{
if (m > n) return 0;
LL Inv = inv[m]*inv[n-m]%g;
return fac[n]*Inv%g;
}
LL Lucas(LL n,LL m,LL g)
{
if (!m) return 1;
return Lucas(n/g,m/g,g)*C(n%g,m%g,g)%g;
}
LL ksm(LL x,int y,LL g)
{
LL ret = 1;
for (; y; y >>= 1)
{
if (y&1) ret = ret*x%g;
x = x*x%g;
}
return ret;
}
void Work(LL a2)
{
LL sum = 1,r2 = 1;
if (a2 < maxn)
{
fac[0] = 1;
for (LL i = 1; i < a2; i++) fac[i] = fac[i-1]*i%a2;
inv[a2-1] = ksm(fac[a2-1],a2-2,a2);
for (LL i = a2-2; i >= 0; i--) inv[i] = inv[i+1]*(i+1)%a2;
sum = Lucas(K + M - 1,M,a2);
}
else
{
for (LL i = 1; i <= M; i++)
{
sum = sum*(K + M - i)%a2; LL x,y;
Extend_Gcd(i,x,a2,y);
sum = sum*x%a2;
}
}
for (int i = 0; i < N; i++) r2 = r2*(sum-i)%a2;
r2 = (r2 + a2) % a2;
if (!a1) {r1 = r2; a1 = a2; return;}
LL x,y,k1,g; Extend_Gcd(a1,x,a2,y);
k1 = (r2 - r1)*x%a2; k1 = (k1 + a2) % a2;
g = a1*a2; r1 = (k1*a1%g + r1) % g; a1 = g;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
for (int i = 2; i < maxn; i++)
{
if (!not_pri[i]) pri[++tot] = i;
for (int j = 1; j <= tot; j++)
{
int Nex = i*pri[j];
if (Nex >= maxn) break;
not_pri[Nex] = 1;
if (i % pri[j] == 0) break;
}
}
cin >> N >> M >> K >> P; int _P = P;
for (int i = 1; i <= tot; i++)
{
if (_P % pri[i] != 0) continue;
while (_P % pri[i] == 0) _P /= pri[i];
Work(pri[i]);
}
if (_P > 1) Work(_P);
cout << r1;
return 0;
}