逆序对
题解
首先,看到这道题,应该很容易想到
d
p
dp
dp。
我们将所有的数字从小到大加入,当加入数字
i
i
i时,它有
i
i
i个可选择位置,可能产生
[
0
,
i
−
1
]
[0,i-1]
[0,i−1]个逆序对。
所以容易联想到生成函数,
A
n
s
=
(
∏
i
=
1
n
(
∑
j
=
0
i
−
1
x
j
)
)
[
x
k
]
=
(
∏
i
=
1
n
1
−
x
i
1
−
x
)
[
x
k
]
=
∏
i
=
1
n
(
1
−
x
i
)
(
1
−
x
)
n
Ans=(\prod_{i=1}^{n}(\sum_{j=0}^{i-1}x^j))[x^k]=(\prod_{i=1}^{n}\frac{1-x^i}{1-x})[x^k]=\frac{\prod_{i=1}^{n}(1-x^i)}{(1-x)^n}
Ans=(i=1∏n(j=0∑i−1xj))[xk]=(i=1∏n1−x1−xi)[xk]=(1−x)n∏i=1n(1−xi)
对于分母
1
(
1
−
x
)
n
\frac{1}{(1-x)^n}
(1−x)n1,它是与
∑
j
=
0
(
j
+
n
−
1
n
−
1
)
x
j
\sum_{j=0}\binom{j+n-1}{n-1}x^j
∑j=0(n−1j+n−1)xj等价的。
由于,
1
(
1
−
x
)
n
=
(
1
+
x
+
x
2
+
.
.
.
+
x
n
)
n
\frac{1}{(1-x)^n}=(1+x+x^2+...+x^n)^n
(1−x)n1=(1+x+x2+...+xn)n,那么对于
x
i
x^i
xi,它的次数可以被划分成
n
n
n段,对应每一种乘到它的路径,划分数可以用隔板法进行理解,我们最后有
i
i
i个空位与
n
−
1
n-1
n−1个隔板,相当于我们要从最开始的
i
+
n
−
1
i+n-1
i+n−1个元素中选出
n
−
1
n-1
n−1个隔板,系数为
(
j
+
n
−
1
n
−
1
)
\binom{j+n-1}{n-1}
(n−1j+n−1)。
而对于我们的分子,相当于我们有
n
n
n个价值分别为
1
,
2
,
3
,
.
.
.
,
n
1,2,3,...,n
1,2,3,...,n的物品,我们要选出一些物品,使他们的价值总和为
i
i
i,如果选择的物品数量为奇数,贡献就为
−
1
-1
−1,数量为偶数贡献就为
1
1
1,求所有方法的贡献和。
由于所有物品的价值不相同,所以我们选择的物品数量是
n
\sqrt{n}
n级别的,我们可以用
d
p
dp
dp来进行处理。
我们令
d
p
i
,
j
dp_{i,j}
dpi,j表示已经选择了
i
i
i个物品,它们的总和为
j
j
j。
d
p
dp
dp的转移我们可以考虑采取那种一层一层消的思路,转移有两类:
- 让已经选择了的所有的物品的权值加 1 1 1。
- 在上一个操作的基础上再加入一个权值为 1 1 1的物品。
容易得到状态转移方程式,
d
p
i
,
j
=
d
p
i
−
1
,
j
−
i
+
d
p
i
,
j
−
i
−
[
j
>
n
]
d
p
i
−
1
,
j
−
n
−
1
dp_{i,j}=dp_{i-1,j-i}+dp_{i,j-i}-[j>n]dp_{i-1,j-n-1}
dpi,j=dpi−1,j−i+dpi,j−i−[j>n]dpi−1,j−n−1
后面减去
d
p
i
−
1
,
j
−
n
dp_{i-1,j-n}
dpi−1,j−n是为了排除选择物品的价值超过
n
n
n的情况,由于我们一次只会加一,所以价值超过
n
n
n的物体都是从合法状态转移而来的,价值刚好为
n
+
1
n+1
n+1,将其减去剩下的都是合法的了。
然后再将两部分合并在一起就可以得到答案了,由于我们求的只是
x
k
x^k
xk这一项的系数,完全没必要通过
N
T
T
NTT
NTT来进行合并,直接乘在一起即可,答案即为
A
n
s
=
∑
i
=
0
n
(
−
1
)
i
∑
j
=
0
k
(
k
−
j
+
n
−
1
n
−
1
)
d
p
i
,
j
Ans=\sum_{i=0}^{n}(-1)^i\sum_{j=0}^{k}\binom{k-j+n-1}{n-1}dp_{i,j}
Ans=i=0∑n(−1)ij=0∑k(n−1k−j+n−1)dpi,j
时间复杂度 O ( k l o g k + n ) O\left(klog\,k+n\right) O(klogk+n)
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 200005
#define MAXM 100005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const int mo=1e9+7;
const int jzm=2333;
const int lim=10000000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<int,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){if(x<0){x=(~x)+1;putchar('-');}if(x>9)print(x/10);putchar(x%10+'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
int n,k,fac[MAXN],inv[MAXN],f[MAXN],dp[2][MAXM],g[MAXM],ans;
void init(){
fac[0]=fac[1]=inv[0]=inv[1]=f[1]=1;
for(int i=2;i<=n+k;i++){
fac[i]=1ll*i*fac[i-1]%mo;
f[i]=1ll*(mo-mo/i)*f[mo%i]%mo;
inv[i]=1ll*f[i]*inv[i-1]%mo;
}
}
int C(int x,int y){
if(x<0||y<0||x<y)return 0;
return 1ll*fac[x]*inv[y]%mo*inv[x-y]%mo;
}
signed main(){
read(n);read(k);init();dp[0][0]=1;
for(int i=0;i<=k;i++)g[i]=C(i+n-1,n-1);ans=g[k];
for(int i=1;i<=n;i++){
if(1ll*i*(i+1)/2LL>k)break;
int now=i&1,las=now^1;
for(int j=i;j<=k;j++){
dp[now][j]=add(dp[las][j-i],dp[now][j-i],mo);
if(j>n)dp[now][j]=add(dp[now][j],mo-dp[las][j-n-1],mo);
if(i&1)ans=add(ans,mo-1ll*g[k-j]*dp[now][j]%mo,mo);
else ans=add(ans,1ll*g[k-j]*dp[now][j]%mo,mo);
}
for(int j=i-1;j<=k;j++)dp[las][j]=0;
}
printf("%d\n",ans);
return 0;
}