loj#6077 「2017 山东一轮集训 Day7」逆序对
不难发现所求即\((1+x)(1+x+x^2)(1+x+x^2+x^3)...(1+x+x^2+x^3+...+x^{n-1})\)的\(k\)此项系数
由于\((1+x+x^2+x^3+...+x^i)=\frac{1-x^{i+1}}{1-x}\),所以我们要求的多项式即\(\frac{\prod _{i=1}^n (1-x^i)}{(1-x)^n}\),分母就是一个组合数,分子上先取一个\(\ln\)再\(\exp\)回去,即\(\ln(1-x^i)=\sum_{k=1}^\infty \frac{1}{k}x^{ki}\)
但由于模数的问题上面的东西随便说说就好了
考虑换个方式求\(\prod _{i=1}^n (1-x^i)\);显然有一个叫背包的东西,但是复杂度是\(O(nk)\)的,但是我们注意到背包里的物品是\(\sqrt{k}\)级别,于是可以设\(g_{i,j}\)表示当前背包里有\(i\)个物品和为\(j\)
我们可以使得背包里每一个物品都加\(1\),即\(g_{i,j}+=g_{i,i-j}\);也可以使背包每一个物品都加\(1\)之后新增一个物品,即\(g_{i,j}+=g_{i-1,j-i}\)
但是我们通过这样的方法构造出来的背包中可能某个物品的体积大于\(n\),所以在大于\(n\)的时候,有\(g_{i,j}-=g_{i-1,j-n-1}\),可惜的是我看不太透这里为什么要这么搞,所以哪位老哥交交我啊
之后慎老师就教育了我
不难发现原来的\(g_{i,j-i},g_{i-1,j-i}\)中最大的物品也就是\(n\),于是体积加\(1\)转移过来最多只会有一个\(n+1\)的物品,显然可以由一个\(i-1\)个物品,体积和为\(j-n-1\)的背包新增一个体积为\(n+1\)的物品得到
代码
#include<bits/stdc++.h>
#define re register
const int mod=1e9+7;
const int maxn=2e5+5;
inline int dqm(int x) {return x<0?x+mod:x;}
inline int qm(int x) {return x>=mod?x-mod:x;}
int dp[maxn>>1],g[451][maxn>>1],ans,n,k,fac[maxn],ifac[maxn];
inline int C(int n,int m) {return m>n?0:1ll*fac[n]*ifac[n-m]%mod*ifac[m]%mod;}
inline int ksm(int a,int b) {int S=1;for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)S=1ll*S*a%mod;return S;}
int main() {
scanf("%d%d",&n,&k);fac[0]=ifac[0]=1;
for(re int i=1;i<=n+k;i++) fac[i]=1ll*fac[i-1]*i%mod;
ifac[n+k]=ksm(fac[n+k],mod-2);
for(re int i=n+k-1;i;--i) ifac[i]=1ll*ifac[i+1]*(i+1)%mod;dp[0]=1;g[0][0]=1;
int T=450;dp[0]=1;
for(re int i=1;i<=T;++i)
for(re int j=1;j<=k;j++) {
if(j>=i) g[i][j]=g[i][j-i];
if(j>i) g[i][j]=qm(g[i][j]+g[i-1][j-i-1]);
if(j>n) g[i][j]=dqm(g[i][j]-g[i-1][j-n-1]);
if(i&1) dp[j]=dqm(dp[j]-g[i][j]);else dp[j]=qm(dp[j]+g[i][j]);
}
n--;for(re int i=0;i<=k;i++) ans=qm(ans+1ll*C(n+k-1-i,n-1)*dp[i]%mod);
printf("%d\n",ans);
}