[CEOI2004] Sweets
\(\text{Problem}:\)[CEOI2004] Sweets
\(\text{Solution}:\)
要求的是:
考虑 \([w_{i}\leq m_{i}]\) 的 \(\text{OGF}\),有:
带回到原式中,得到答案及其生成函数为:
发现 \(\prod\limits_{i=1}^{n}(1-x^{m_{i}+1})\) 最多只有 \(2^{n}\) 个项的系数不为 \(0\),而 \(n\leq 10\),故可以暴力展开。现在考虑处理 \((1-x)^{-n}\),有:
引理 \(1\)(广义二项式系数):
引理 \(2\)(关于二项式系数的恒等式):
证明:将等号左右两边展开,根据 \(k\) 的奇偶性分类讨论即可。
回到 \((1-x)^{-n}\),由引理 \(2\),得到:
枚举 \(\prod\limits_{i=1}^{n}(1-x^{m_{i}+1})\) 的系数非零项,记第 \(k\) 项的系数为 \(h_{k}\),则它对答案的贡献为:
由 \(\binom{n}{m}=\binom{n-1}{m}+\binom{n-1}{m-1}\),得到:
要计算的组合数是 \(\binom{n+i}{i}\) 的形式,而模数为 \(2004\),不能直接用逆元来求。比较常规的做法是扩展卢卡斯,这里介绍另一种做法。
展开 \(\binom{n+i}{i}\),得到:
设 \(S=(n+i)(n+i-1)\cdot\cdot\cdot(i+1)=k_{1}(2004\cdot n!)+r,k\in\Z\),\(\dfrac{S}{n!}≡X\text{ (mod 2004)}\),有:
而又有 \(S≡r\text{ (mod (2004}\cdot n!))\),所以计算 \(S\) 时对 \((2004\cdot n!)\) 取模得到 \(r\),除以 \(n!\) 再对 \(2004\) 取模就求出了组合数。
总时间复杂度 \(O(n2^{n})\)。
\(\text{Code}:\)
#include <bits/stdc++.h>
#pragma GCC optimize(3)
#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=15;
inline int read()
{
int s=0, w=1; ri char ch=getchar();
while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
return s*w;
}
int n,A,B,a[N],ans,fac;
inline int C(int x,int y)
{
int res=1;
for(ri int i=x-y+1;i<=x;i++) res=res*i%(fac*2004);
return (res/fac)%2004;
}
void DFS(int x,int xs,int cs,int goal)
{
if(cs>goal) return;
if(x==n+1)
{
ans=(ans+xs*C(n+goal-cs,n)%2004+2004)%2004;
return;
}
DFS(x+1,xs,cs,goal);
DFS(x+1,-xs,cs+a[x]+1,goal);
}
int Solve(int goal)
{
ans=0;
DFS(1,1,0,goal);
return ans;
}
signed main()
{
n=read(), A=read(), B=read();
for(ri int i=1;i<=n;i++) a[i]=read();
fac=1;
for(ri int i=1;i<=n;i++) fac*=i;
printf("%lld\n",(Solve(B)-Solve(A-1)+2004)%2004);
return 0;
}