题解:P10254 口吃
想办法把一个排列的权值往逆序对数量上靠。
可以拆式子
发现这三项都可以 DP 做。
设
对于
对于
答案为:
时间复杂度
注:代码中为了方便,转移
::::info[代码]
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll mod = 998244353;
const ll inv2 = 499122177;
void Add(int &x, int y){(x += y) >= mod ? x -= mod : 0;}
int add(int x, int y){Add(x, y); return x;}
const int kN = 301;
int n, k, f[2][kN * kN], g[2][kN * kN], h[2][kN * kN];
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> k;
h[1][0] = 1;
for(int i = 2; i <= n; i++){
memcpy(f[0], f[1], sizeof(f[1]));
memcpy(h[0], h[1], sizeof(h[1]));
memset(f[1], 0, sizeof(f[1]));
memset(h[1], 0, sizeof(h[1]));
for(int j = 0; j <= i * (i - 1) / 2; j++){
for(int k = 0; k < i; k++){
if(j >= k){
Add(h[1][j], h[0][j - k]);
Add(f[1][j], f[0][j - k]);
Add(f[1][j], h[0][j - k] * 1ll * (i - 1 - k) % mod * i % mod);
}
}
}
}
int ans = 1ll * n * (n + 1) % mod * inv2 % mod * h[1][k] % mod;
Add(ans, f[1][k]);
memset(h[1], 0, sizeof(h[1]));
h[1][0] = 1;
for(int i = n - 1; i >= 1; i--){
memcpy(g[0], g[1], sizeof(g[1]));
memcpy(h[0], h[1], sizeof(h[1]));
memset(g[1], 0, sizeof(g[1]));
memset(h[1], 0, sizeof(h[1]));
for(int j = 0; j <= (n - i) * (n - i + 1) / 2; j++){
for(int k = 0; k <= n - i; k++){
if(j >= k){
Add(h[1][j], h[0][j - k]);
Add(g[1][j], g[0][j - k]);
Add(g[1][j], h[0][j - k] * 1ll * k % mod * i % mod);
}
}
}
}
Add(ans, g[1][k]);
cout << ans << '\n';
return 0;
}
::::
发现
时间复杂度
::::info[代码]
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll mod = 998244353;
const ll inv2 = 499122177;
void Add(int &x, int y){(x += y) >= mod ? x -= mod : 0;}
int add(int x, int y){Add(x, y); return x;}
const int kN = 301;
int n, k, f[2][kN * kN], g[2][kN * kN], h[2][kN * kN];
int sh[kN * kN], sf[kN * kN], sg[kN * kN], sh2[kN * kN], sg2[kN * kN], sh3[kN * kN];
signed main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> k;
h[1][0] = 1;
for(int i = 0; i <= n * (n - 1) / 2; i++) sh[i] = sh2[i] = 1;
for(int i = 2; i <= n; i++){
memcpy(f[0], f[1], sizeof(f[1]));
memcpy(h[0], h[1], sizeof(h[1]));
memset(f[1], 0, sizeof(f[1]));
memset(h[1], 0, sizeof(h[1]));
for(int j = 0; j <= i * (i - 1) / 2; j++){
int l = min(j, i - 1);
f[1][j] = (sh2[j] - (j > l ? sh2[j - l - 1] : 0) + mod) % mod;
Add(f[1][j], mod - (sh[j] - (j > l ? sh[j - l - 1] : 0) + mod) % mod * 1ll * j % mod);
f[1][j] = f[1][j] * 1ll * i % mod;
Add(h[1][j], (sh[j] - (j > l ? sh[j - l - 1] : 0) + mod) % mod);
Add(f[1][j], (sf[j] - (j > l ? sf[j - l - 1] : 0) + mod) % mod);
}
sh[0] = h[1][0], sh2[0] = h[1][0] * 1ll * i % mod, sf[0] = f[1][0];
for(int j = 1; j <= n * (n - 1) / 2; j++){
sh[j] = add(sh[j - 1], h[1][j]);
sh2[j] = add(sh2[j - 1], h[1][j] * 1ll * (i + j) % mod);
sf[j] = add(sf[j - 1], f[1][j]);
}
}
int ans = 1ll * n * (n + 1) % mod * inv2 % mod * h[1][k] % mod;
Add(ans, f[1][k]);
memset(h[1], 0, sizeof(h[1]));
h[1][0] = 1;
for(int i = 0; i <= n * (n - 1) / 2; i++) sh[i] = 1;
for(int i = n - 1; i >= 1; i--){
memcpy(g[0], g[1], sizeof(g[1]));
memcpy(h[0], h[1], sizeof(h[1]));
memset(g[1], 0, sizeof(g[1]));
memset(h[1], 0, sizeof(h[1]));
for(int j = 0; j <= (n - i) * (n - i + 1) / 2; j++){
int l = min(j, n - i);
g[1][j] = mod - (sh3[j] - (j > l ? sh3[j - l - 1] : 0) + mod) % mod;
Add(g[1][j], (sh[j] - (j > l ? sh[j - l - 1] : 0) + mod) % mod * 1ll * j % mod);
g[1][j] = g[1][j] * 1ll * i % mod;
Add(h[1][j], (sh[j] - (j > l ? sh[j - l - 1] : 0) + mod) % mod);
Add(g[1][j], (sg[j] - (j > l ? sg[j - l - 1] : 0) + mod) % mod);
}
sh[0] = h[1][0], sh3[0] = 0, sg[0] = g[1][0];
for(int j = 1; j <= n * (n - 1) / 2; j++){
sh[j] = add(sh[j - 1], h[1][j]);
sh3[j] = add(sh3[j - 1], h[1][j] * 1ll * j % mod);
sg[j] = add(sg[j - 1], g[1][j]);
}
}
Add(ans, g[1][k]);
cout << ans << '\n';
return 0;
}
::::