Solution
- 组合数学 \(+\) 前缀和优化\(dp\)
- 考虑\(P1[l...r]\)和\(P2[l...r]\)离散化后的排列\(P[1...r-l+1]\)
- 令\(i=r-l+1\)
- 那么离散化后为\(P\)的子串会在\(C(n,i)*(n-i)!\)种长度为\(n\)的排列中出现(假设这个子串必须放在\([1...i]\))
- 解释:\(1\)到\(n\)中选\(i\)个数,先排成和\(P\)相似的子串
- 为防止一种长度为\(n\)的排列中,出现多个离散化后为\(P\)的子串导致一种排列算多次,固定这个子串放在位置\([1...i]\)
- 剩下的\(n-i\)个位置,\(n-i\)个数可以随便排列
- 设\(sum[i][j]\)表示\(1...i\)的所有排列中,逆序对数不超过\(j\)的有多少种
- 那么答案就是\(\sum_{i=1}^{n}sum[i][min(E,i*(i-1)/2)]*(C(n,i)*(n-i)!)^2*(n-i+1)\)
- 解释:依照上文可以构造出\((C(n,i)*(n-i)!)^2\)组合法的,且子串放在位置\([1...i]\)的\((P1,P2)\)
- 然后考虑这个子串的开头放在哪,由于\(P1\)和\(P2\)的相似子串要在相同位置,所以乘上\(n-i+1\)
- 问题转化为求\(sum[i][j]\)
- 设\(f[i][j]\)表示\(1\)到\(i\)的所有排列中,逆序对数正好为\(j\)的有多少种
- 考虑枚举\(i\)放在倒数第\(k+1\)个位置
- 那么会产生新的\(k\)组逆序对,即\(f[i][j]+=f[i-1][j-k]\)
- \(k\)的取值为\(0\)到\(i-1\),所以\(f[i][j]=sum[i-1][j]-sum[i-1][j-i]\)
- 注意特判\(j-i<0\)的情况
- 时间复杂度\(O(Tn+n^3)\)
Code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
template <class t>
inline void read(t & res)
{
char ch;
while (ch = getchar(), !isdigit(ch));
res = ch ^ 48;
while (ch = getchar(), isdigit(ch))
res = res * 10 + (ch ^ 48);
}
const int e = 505, o = 124760, mod = 1e9 + 7;
int n, sum[e][o], ans, c[e][e], tst, m, fac[e];
inline void upt(int &x, int y)
{
x = y;
if (x >= mod) x -= mod;
}
inline void add(int &x, int y)
{
x += y;
if (x >= mod) x -= mod;
}
int main()
{
int i, j, k;
sum[1][0] = sum[1][1] = 1;
for (i = 2; i <= 500; i++)
{
k = i * (i - 1) / 2;
for (j = 0; j <= k; j++)
upt(sum[i][j], sum[i - 1][j] + (j >= i ? mod - sum[i - 1][j - i] : 0));
k = i * (i + 1) / 2;
for (j = 1; j <= k; j++) add(sum[i][j], sum[i][j - 1]);
}
fac[0] = 1;
for (i = 1; i <= 500; i++) fac[i] = (ll)fac[i - 1] * i % mod;
for (i = 0; i <= 500; i++)
for (j = 0; j <= i; j++)
if (i == j || j == 0) c[i][j] = 1;
else upt(c[i][j], c[i - 1][j] + c[i - 1][j - 1]);
read(tst);
while (tst--)
{
read(n); read(m);
ans = 0;
for (i = 1; i <= n; i++)
{
int len = min(m, i * (i - 1) / 2);
add(ans, (ll)sum[i][len] * (n - i + 1) % mod
* c[n][i] % mod * fac[n - i] % mod * c[n][i] % mod * fac[n - i] % mod);
}
printf("%d\n", ans);
}
return 0;
}