题意
给,,求出长度为的逆序对数恰好为的排列的个数。
思路
考虑从小到大插入(偏序类题目常用方法:定序)。对逆序对数的贡献必为。
还有一个贡献和为的限制。考虑生成函数。
因此枚举找到累计起来即可。
而是互异分拆的生成函数。
互异的数的数量
因此用dp+根号分治的方法,表示选择个和为的方案数。
这里有一个我没有搞懂的地方:为什么时,要去把算进去的重,为什么不去掉之类的呢。我还会再思考一下的……
code
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
const int mod=1e9+7;
ll ksm(ll a,ll b) {ll mul=1;for(;b;b>>=1,a=a*a%mod)if(b&1)mul=mul*a%mod;return mul;}
int n,k,S;
ll jc[N],ijc[N],f[2][N],g[N];
int _pd(int x) {return (x&1)?-1:1;}
void _pre() {
S=(int)ceil(sqrt(k))*2;
f[0][0]=1;g[0]=1;
for(int i=1;i<=S;i++) {
bool o=i&1,_o=o^1;
for(int j=0;j<i;j++) {f[o][j]=0;}
// memset(f[o],0,sizeof(f[o]));
for(int j=i;j<=k;j++) {
f[o][j]=(f[o][j-i]+f[_o][j-i])%mod;
if(j>n) {f[o][j]=(f[o][j]-f[_o][j-n-1])%mod;}
g[j]=(g[j]+_pd(o)*f[o][j])%mod;
}
}
int up=n+k;
jc[0]=1;for(int i=1;i<=up;i++)jc[i]=jc[i-1]*i%mod;
ijc[up]=ksm(jc[up],mod-2);for(int i=up;i;i--)ijc[i-1]=ijc[i]*i%mod;
}
ll binom(int a,int b) {return jc[a]*ijc[b]%mod*ijc[a-b]%mod;}
void solve() {
ll ans=0;
for(int j=0;j<=k;j++) {
ans=(ans+binom(j+n-1,j)*g[k-j])%mod;
}
printf("%lld",(ans+mod)%mod);
}
int main() {
scanf("%d%d",&n,&k);
_pre();
solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人