不等式
给定如下不等式组
[∀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),那么后面的变量方案数可以用组合数算出答案就是 (inom{S−X}{m−n})。
把 (inom{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)^2log 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
",mul(ans,ifac[m]));
return 0;
}