CF1542E1 Abnormal Permutation Pairs (easy version) 题解
不会 Hard version
对于第一个限制字典序,我们可以考虑枚举前 \(i\) 位相同,然后考虑后 \(n-i\) 位。我们只需要保证 \(p_{i+1} < q_{i+1}\) 即可。
我们设 \(len = n - i\)。由于前 \(i\) 位完全相同,所以前 \(i\) 位内部的逆序对个数以及前 \(i\) 位与后 \(len\) 位之间产生的逆序对个数也是相同的,因此对于第二个条件,我们只需要满足 \(p\) 后 \(len\) 位的逆序对个数严格大于 \(q\) 的后 \(len\) 位的即可。
因为逆序对仅与相对大小有关,所以后 \(len\) 位可以抽象成一个 \(1\) 到 \(len\) 的排列。我们设 \(f_{len, j, k}\) 表示长度为 \(len\) 的排列,第一位是 \(j\),有 \(k\) 个逆序对的方案数。则长度每增加一位,只用考虑新加入的 \(len\) 作为开头以及其他数作为开头的转移。有:
对于第一种转移,我们只需把上一层所有数作为开头的方案加起来;对于第二种转移,我们考虑 \(len\) 插入到除了开头以外的其他位置产生的新的逆序对即可。
其中第二个转移是 \(O(n^5)\) 的,我们发现枚举的 \(t\) 是一个区间内的答案,所以可以前缀和优化可以到 \(O(n^4)\)。
然后我们来考虑统计答案。我们设逆序对个数上界 \(mx = \frac{len \times (len-1)}{2}\),\(sp\)、\(sq\) 分别为 \(p\) 和 \(q\) 中后 \(len\) 位的逆序对个数,一个朴素的答案式子如下:
我们从 \(n\) 中选取 \(len\) 个数作为后缀,则剩下的 \(n-len\) 个数做前缀。前缀要求完全相同,但可以随意排列顺序。后半部分就是通过枚举来满足第一和第二个限制。
显然是一个 \(O(n^7)\) 的式子。我们调整一下这个式子:
会发现后半部分是个矩形内的和,可以用二维前缀和优化到 \(O(1)\) 求出。前半部分枚举是 \(O(n^4)\) 的。
简单版就做完了,复杂度 \(O(n^4)\)。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 54;
int mod;
void add(int &a, int b) {
a = (a+b)%mod;
}
int f[N][N][N*N];
int n;
int fac[N];
int sum1[N][N][N*N];//第一个前缀和(可以滚动数组优化)
int sum2[N][N][N*N];//第二个前缀和(也可以滚动数组)
int C[N][N];
void prework() {
fac[0] = 1;
for(int i = 1; i<=n; ++i) {
fac[i] = 1ll*fac[i-1]*i%mod;
}
C[0][0] = 1;
for(int i = 1; i<=n; ++i) {
C[i][0] = 1;
for(int j = 1; j<=i; ++j) {
C[i][j] = (C[i-1][j] + C[i-1][j-1])%mod;
}
}//预处理阶乘和组合数
}
int main() {
scanf("%d%d", &n, &mod);
prework();
f[1][1][0] = 1;
for(int i = 2; i<=n; ++i) {
for(int j = 1; j<i; ++j) {
for(int k = i-1; k<=(i*(i-1)/2); ++k) {
add(f[i][i][k], f[i-1][j][k-(i-1)]);
}
}//新加入一个最大的数,让它作为开头
for(int j = 1; j<i; ++j) {
sum1[i-1][j][0] = f[i-1][j][0];
for(int o = 1; o<=(i*(i-1)/2); ++o) {
sum1[i-1][j][o] = f[i-1][j][o];
add(sum1[i-1][j][o], sum1[i-1][j][o-1]);
}//计算需要的前缀和
for(int o = 0; o<=(i*(i-1)/2); ++o) {
if(o > i-2) {
add(f[i][j][o], (sum1[i-1][j][o] - sum1[i-1][j][o-(i-2)-1])%mod);
if(f[i][j][o] < 0) f[i][j][o]+=mod;
} else f[i][j][o] = sum1[i-1][j][o];
}
}//对于其他数作为开头的情况
}
int ans = 0;
for(int i = 0; i<n-1; ++i) {
int ret = 1ll*fac[i]*C[n][i]%mod;
int len = n-i;
int sum = 0;
for(int j = 1; j<=len; ++j) {
sum2[len][j][0] = f[len][j][0];
add(sum2[len][j][0], sum2[len][j-1][0]);
for(int k = 1; k<=(len*(len-1)/2); ++k){
sum2[len][j][k] = f[len][j][k];
add(sum2[len][j][k], (1ll * sum2[len][j][k-1] + 1ll * sum2[len][j-1][k] + 1ll * mod - 1ll*sum2[len][j-1][k-1])%mod);
}
}//预处理二维前缀和。
for(int j = 1; j<=len; ++j) {
for(int oa = 1; oa<=(len*(len-1)/2) ;++oa) {
add(sum, 1ll*f[len][j][oa] * (1ll*sum2[len][len][oa-1] - sum2[len][j][oa-1])%mod);
}
}
add(ans, 1ll*ret*sum%mod);
}
if(ans<0) ans+=mod;
printf("%d\n", ans);
return 0;
}
- 题解 Permutation Abnormal version 1542E题解permutation abnormal version 题解 前缀permutation abnormal permutation problem version 1909f permutation codeforces problem version 题解permutation 167d good 题解permutation another problem 题解permutation p7972 2021 题解permutation 213e two 线段 题解permutation separation 题解permutation oddness 134f