BZOJ3284 不等式
不等式
给定如下不等式组
\[∀1 ≤ i ≤ n, x_i ≤ t\\
\sum_{i=1}^m x_i ≤ S
\]
给定 \(S,t, n, m\),求解数。
-
\(S ≤ 10^{18}\)
-
\(n ≤ m ≤ 10^9\)
-
\(t ≤ 10^9,n ⋅ t ≤ S\)
-
\(m − n ≤ 10^3\)
题解
仓鼠《杂题选讲》。
假如暴力枚举前\(n\)个变量的取值,令它们的和为\(X\),那么后面的变量方案数可以用组合数算出答案就是 \(\binom{S−X}{m−n}\)。
把 \(\binom{S−X}{m−n}\) 展开成一个关于\(x\)的\(m − n\)次多项式\(F(x)\)。
那么只要对于每个\(0 ≤ k ≤ m − n\)的\(k\),均计算出\(\sum_{∀1≤i≤n,x_i≤t}(x_1 +x_2 + ⋯ + x_n)^k\),然后代入到\(F(x)\)里面即可。
记一个长度为\(m − n + 1\)的向量\(G_l\),其中\(G_{l,k}\)表示的就是\(\sum_{∀1≤i≤l,x_i≤t}(x_1 +x_2 + ⋯ + x_l)^k\) ,不难发现由\(G_a\)和\(G_b\)可以直接\(O( (m − n)^2)\)求出\(G_{a+b}\)。直接倍增算出\(G_n\)即可。
时间复杂度 \(O((m-n)^2\log n)\)。
CO int N=1e3+10;
int fac[N],ifac[N];
IN int C(int n,int m){
return mul(fac[n],mul(ifac[m],ifac[n-m]));
}
int lagrange(int n,int T){
static int val[N];
for(int i=1;i<=n+2;++i) val[i]=add(val[i-1],fpow(i,n));
static int pre[N],suf[N];
pre[0]=1;
for(int i=1;i<=n+2;++i) pre[i]=mul(pre[i-1],T+mod-i);
suf[n+3]=1;
for(int i=n+2;i>=1;--i) suf[i]=mul(suf[i+1],T+mod-i);
int ans=0;
for(int i=1;i<=n+2;++i){
int sum=mul(val[i],mul(pre[i-1],suf[i+1]));
sum=mul(sum,mul(ifac[i-1],ifac[n+2-i]));
ans=add(ans,(n+2-i)%2==0?sum:mod-sum);
}
return ans;
}
poly operator+(CO poly&a,CO poly&b){
int n=a.size()-1;
poly ans(n+1);
for(int i=0;i<=n;++i)for(int j=0;j<=i;++j)
ans[i]=add(ans[i],mul(C(i,j),mul(a[j],b[i-j])));
return ans;
}
poly operator*(CO poly&a,CO poly&b){
int n=a.size()-1,m=b.size()-1;
poly ans(n+m+1);
for(int i=0;i<=n;++i)for(int j=0;j<=m;++j)
ans[i+j]=add(ans[i+j],mul(a[i],b[j]));
return ans;
}
int main(){
fac[0]=1;
for(int i=1;i<N;++i) fac[i]=mul(fac[i-1],i);
ifac[N-1]=fpow(fac[N-1],mod-2);
for(int i=N-2;i>=0;--i) ifac[i]=mul(ifac[i+1],i+1);
int64 S=read<int64>();int T=read<int>();
int n=read<int>(),m=read<int>()-n;
poly g(m+1);
for(int i=0;i<=m;++i) g[i]=lagrange(i,T);
poly f(m+1);f[0]=1;
for(;n;n>>=1,g=g+g) if(n&1) f=f+g;
poly p={1};
for(int i=0;i<m;++i) p=p*(poly){int((S-i)%mod),mod-1};
int ans=0;
for(int i=0;i<=m;++i) ans=add(ans,mul(p[i],f[i]));
printf("%d\n",mul(ans,ifac[m]));
return 0;
}
静渊以有谋,疏通而知事。