1 条题解
-
0
自动搬运
来自洛谷,原作者为

mrclr
**搬运于
2025-08-24 22:02:12,当前版本为作者最后更新于2019-05-27 22:40:20,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
如果没有限制,而且必须选件的话,就是隔板法了。现在要选至多件,那么就相当于新增一个板儿,分出的新的盒子表示“多出来的”,也就是说前个盒子是选出来的宝具,这样就能满足至多个的限制了,即。
从公式这一角度来说,就是$\sum _ {i = 0} ^ {n} C_ {i + m - 1} ^ {m - 1} = C_{n + m} ^ {m}$,至于证明,在我的另一篇博客上有,题解:bzoj4403 序列统计。
现在我们加上了这个限制。我一直在想,这么小,显然可以暴力枚举,但那又有啥用咧?
后来某大佬的题解告诉我,你怎么就想不到容斥啊?
好像有道理,答案等于至少0个神器超过限制的方案数 - 至少1个神器超过限制方案数 + 至少3个超过限制 - ……而对于每一个方案数,我们先强制让这些神器选个,然后剩下的随便选,就是$C_{n + m - \sum(B_i + 1)} ^ {m - \sum (B_i + 1)} = C_{n + m - \sum(B_i + 1)} ^ {n}$。
最后因为模数小,上lucas。
#include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<cstring> #include<cstdlib> #include<cctype> #include<vector> #include<stack> #include<queue> #include<assert.h> using namespace std; #define enter puts("") #define space putchar(' ') #define Mem(a, x) memset(a, x, sizeof(a)) #define In inline typedef long long ll; typedef double db; const int INF = 0x3f3f3f3f; const db eps = 1e-8; const int maxn = 1e6 + 5; In ll read() { ll ans = 0; char ch = getchar(), last = ' '; while(!isdigit(ch)) last = ch, ch = getchar(); while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar(); if(last == '-') ans = -ans; return ans; } In void write(ll x) { if(x < 0) x = -x, putchar('-'); if(x >= 10) write(x / 10); putchar(x % 10 + '0'); } In void MYFILE() { #ifndef mrclr freopen(".in", "r", stdin); freopen(".out", "w", stdout); #endif } int n, T, m, mod, b[20]; ll fac[maxn], inv[maxn]; In ll inc(ll a, ll b) {return a + b < mod ? a + b : a + b - mod;} In ll C(int n, int m) { if(m > n) return 0; return fac[n] * inv[n - m] % mod * inv[m] % mod; } In ll lucas(int n, int m) { ll ret = 1; for(; m; n /= mod, m /= mod) ret = ret * C(n % mod, m % mod) % mod; return ret; } In ll quickpow(ll a, ll b) { ll ret = 1; for(; b; b >>= 1, a = a * a % mod) if(b & 1) ret = ret * a % mod; return ret; } In void init() { fac[0] = inv[0] = 1; for(int i = 1; i < mod; ++i) fac[i] = fac[i - 1] * i % mod; inv[mod - 1] = quickpow(fac[mod - 1], mod - 2); for(int i = mod - 2; i; --i) inv[i] = inv[i + 1] * (i + 1) % mod; } int main() { //MYFILE(); n = read(), T = read(), m = read(), mod = read(); for(int i = 1; i <= T; ++i) b[i] = read(); init(); ll ans = 0; for(int i = 0; i < (1 << T); ++i) { int cnt = 0, tp = m; for(int j = 1; j <= T; ++j) if((i >> (j - 1)) & 1) ++cnt, tp -= b[j] + 1; ans = inc(ans, (cnt & 1) ? mod - lucas(n + tp, n) : lucas(n + tp, n)); } write(ans), enter; return 0; }
- 1
信息
- ID
- 3596
- 时间
- 1000ms
- 内存
- 250MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者