题目传送门

Description

给定 $ n, k $,请求出长度为 $ n $ 的逆序对数恰好为 $ k $ 的排列的个数。答案对 $ 10 ^ 9 + 7 $ 取模。

对于一个长度为 $ n $ 的排列 $ p $,其逆序对数即满足 $ i < j $ 且 $ p_i > p_j $ 的二元组 $ (i, j) $ 的数量。

一行两个整数 $ n, k $。

一行,表示答案。

对于 $ 20% $ 的数据,$ n, k \leq 20 $;

对于 $ 40% $ 的数据,$ n, k \leq 100 $;

对于 $ 60% $ 的数据,$ n, k \leq 5000 $;

对于 $ 100% $ 的数据,$ 1 \leq n, k \leq 100000, 1 \leq k \leq \binom{n}{2} $。

Solution

可以想到,对于一个排列 \(p\) ,假设 \(s_i\) 表示以 \(i\) 为右端点的逆序对个数,那么可以看出一个 \(s_{1,2,...,n}\) 对应一个唯一的 \(p\) ,而一个 \(s_{1,2,...,n}\) 合法当且仅当 \(\forall i,s_i\le i-1\)。

可以想到我们可以容斥,即枚举哪些点 \(s_i\) 越界了。那么,我们也就只需要求出

\[\prod_{i=1}^{n}(1-x^i)
\]

的前面 \(k\) 项。

这个时候我们就有两种办法,一种是用多项式,取 \(\ln\) ,然后用 \(\ln(1-x)=\sum_{j=1}^{\infty} -\frac{x^j}{j}\) \(\Theta(k\log k)\) 直接多项式 \(\ln,\exp\) 算出来,考场上我就写的这个,不过原题要写任意模数 NTT,估计不是很好写,而且常数很大,可以拿头过。

还有另外一种 \(\Theta(k\sqrt k)\) 做法。你发现选出一个 \(\{1,2,...,n\}\) 的集合还有另外一种选法,即假设你现在有一个递减序列,你每次有两种选择:

  1. 整体加 \(1\)

  2. 整体加 \(1\) 并在后面增加一个 \(1\)

那么,我们就可以进行 dp 了,因为考虑到我们最多使用 \(\sqrt k\) 次操作 \(2\),所以,我们可以设 \(f_{i,j}\) 表示在经过 \(i\) 此操作 \(2\) 后数字总和为 \(j\) 的方案数。

可以得到转移式:

\[f_{i,j}=f_{i,j-i}+f_{i-1,j-i}-f_{i-1,j-n-1}
\]

Code

#include <bits/stdc++.h>
using namespace std; #define Int register int
#define mod 1000000007
#define MAXN 200005 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);} int n,k,upp = 2e5,fac[MAXN],ifac[MAXN],f[505][MAXN];
int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
int qkpow (int a,int b){
int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
return res;
}
void Sub (int &a,int b){a = dec (a,b);}
void Add (int &a,int b){a = add (a,b);}
int binom (int a,int b){return a >= b ? mul (fac[a],mul (ifac[b],ifac[a - b])) : 0;} int F[MAXN]; signed main(){
read (n,k);int up = 500;
fac[0] = 1;for (Int i = 1;i <= upp;++ i) fac[i] = mul (fac[i - 1],i);
ifac[upp] = qkpow (fac[upp],mod - 2);for (Int i = upp;i;-- i) ifac[i - 1] = mul (ifac[i],i);
f[0][0] = 1;
for (Int i = 1;i <= up;++ i)
for (Int j = 0;j <= k;++ j){
if (j >= i) Add (f[i][j],add (f[i][j - i],f[i - 1][j - i]));
if (j >= n + 1) Sub (f[i][j],f[i - 1][j - n - 1]);
}
for (Int S = 0;S <= k;++ S)
for (Int i = 0;i <= up;++ i)
if (i & 1) Sub (F[S],f[i][S]);
else Add (F[S],f[i][S]);
int ans = 0;
for (Int S = 0;S <= k;++ S) Add (ans,mul (F[S],binom (k - S + n - 1,n - 1)));
write (ans),putchar ('\n');
return 0;
}

最新文章

  1. Jquery EeasyUI等框架中图标的处理方法
  2. zabbix3.2.0beta2 监控模版
  3. 开机logo切换逻辑深入研究
  4. MySQL通用优化手册
  5. Graham&#39;s Scan算法
  6. 开通GitHub以及使用笔记
  7. maven search
  8. 搭建自己的SIPserver:开源sipserveropensips的搭建及终端TwInkle的使用
  9. c# p2p 穿透(源码加密)
  10. breakpad是Google开源的一套跨平台工具
  11. HDU3488 Tour [有向环覆盖 费用流]
  12. html5版 音乐播放器
  13. 通过回调函数的理解来进一步理解ajax及其注意的用法
  14. ABP入门系列(1)——通过模板创建MAP版本项目
  15. 064、Weave网络结构分析(2019-04-04 周四)
  16. ASP.NET AJAX入门系列(4):使用UpdatePanel控件(一)
  17. linux获取内存、cpu、负载、网口流量、磁盘信息
  18. swusec的构想,顺便送开学福利——校园网一号多登录演示
  19. dSploitzANTI渗透教程之修改MAC地址与Wifi监听器
  20. eclipse3.3插件更新攻略

热门文章

  1. 解锁 VS Code 更多可能性,轻松入门 WebView
  2. Jmeter的初体验--安装
  3. JAVA 之 每日一记 之 算法 ( 长按键入 )
  4. JUC原子操作类与乐观锁CAS
  5. Kubernetes 组件简介
  6. IDEA使用教程+JRebel破解
  7. Mysql常用sql语句(10)- is null 空值查询
  8. vue-admin-element 页面跳转
  9. C# 动态构建表达式树(二)——构建 Select 和 GroupBy 的表达式
  10. centos8安装php扩展memcached报错