题目链接:https://ac.nowcoder.com/acm/contest/560/B
题意:给定k,s,p三个变量,若s >= x1+x2+x3+...xk,那么,T=x1*x2*x3*...xk,若x1~xk存在一个数不一样则为不同情况,求所有不同情况的T的和(模上p)
思路:先dfs按(k,s)暴力打个表:
然后组合数按(n,m)打个表:
然后就发现,ans[k][s] = comb[k+s][2*k]
k和s范围比较大,组合数求值会t所以套一下卢卡斯递推板
代码:
#include<iostream>
#include <cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<functional>
#include <unordered_map>
#include<queue>
#include<cmath>
#include<unordered_map>
#include<fstream>
#include<ctime>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const int N = 5e6+50;
int F[N], Finv[N], inv[N];//F是阶乘,Finv是逆元的阶乘
void init(int MOD) {
inv[1] = 1;
for (int i = 2; i < N; i++) {
inv[i] = (MOD - MOD / i) * 1ll * inv[MOD % i] % MOD;
}
F[0] = Finv[0] = 1;
for (int i = 1; i < N; i++) {
F[i] = F[i - 1] * 1ll * i % MOD;
Finv[i] = Finv[i - 1] * 1ll * inv[i] % MOD;
}
}
int comb(int n, int m,int MOD) {//comb(n, m)就是C(n, m)
if (m < 0 || m > n) return 0;
return F[n] * 1ll * Finv[n - m] % MOD * Finv[m] % MOD;
}
int main() {
ll k, s;
int p;
scanf("%lld%lld%d", &k, &s, &p);
init(p);
ll n, m;
n = k + s;
m = 2 * k;
ll x = max(log(n) / log(p), log(m) / log(p));
ll res = 1;
for (int i = 0; i < x; i++)
{
res *= p;
}
ll ans = 1;
for (int i = x; i >= 0; i--)
{
ans = ans * comb(n / res, m / res, p)%p;
n %= res;
m %= res;
res /= p;
}
printf("%lld\n", ans);
/*
for (int i = 1; i <= 10; i++)
{
for(int j = 1;j<i;j++)
printf("%4d ", 0);
for (int j = i; j <=10; j++)
printf("%4d ",comb[i+j][2*i]);
cout << endl;
}*/
}