n
<
=
500
,
k
<
=
50
n<=500,k<=50
n<=500,k<=50
这个题的突破口在于利用期望的可加性,计算所有的(x,y)两个位置x<y满足P[x]>P[y]的期望值之和即为答案。
然后这个DP可以通过性质分析+前缀和优化到
O
(
n
2
k
)
O(n^2k)
O(n2k)
我在考场上的方法也可以做到
O
(
n
2
k
)
O(n^2k)
O(n2k)但是求和顺序有点奇怪,导致需要5~7类分类讨论吗,无奈只能打了
O
(
n
3
k
)
O(n^3k)
O(n3k),而标程交换了求和顺序,代码简洁,边界情况基本没有。。。。。。
我的代码:
#include<bits/stdc++.h>
#define maxn 505
#define mod 1000000007
using namespace std;
int n,k,P[maxn];
int dp[2][maxn][maxn][2],sum[3][maxn];
int Sum;
int solve(int a,int b,int l,int r) // (l,r)
{
if(a > b) swap(a,b);
int tmp = max(0,min(a-l,r-b));
Sum -=tmp;
return tmp;
}
int Pow(int base,int k)
{
int ret = 1;
for(;k;k>>=1,base=1ll*base*base%mod)
if(k&1)
ret = 1ll *ret * base % mod;
return ret;
}
int main()
{
freopen("inverse.in","r",stdin);
freopen("inverse.out","w",stdout);
scanf("%d%d",&n,&k);
int K = k;
for(int i=1;i<=n;i++) scanf("%d",&P[i]);
int now = 1 , pre = 0;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
if(P[i] < P[j])
dp[pre][i][j][0] = 1;
else
dp[pre][i][j][1] = 1;
}
for(;k;swap(now,pre),k--)
{
memset(dp[now],0,sizeof dp[now]);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
for(int tp = 0;tp<2;tp++)
if(dp[pre][i][j][tp])
{
Sum = n * (n+1) / 2;
for(int p=1;p<j;p++)
dp[now][p][j][tp] = (dp[now][p][j][tp] + dp[pre][i][j][tp] * 1ll * solve(i,p,0,j)) % mod;
for(int p=i+1;p<=n;p++)
dp[now][i][p][tp] = (dp[now][i][p][tp] + dp[pre][i][j][tp] * 1ll * solve(p,j,i,n+1)) % mod;
for(int p=1;p<=n;p++)
dp[now][p][p+j-i][tp^1] = (dp[now][p][p+j-i][tp^1] + dp[pre][i][j][tp] * 1ll * solve(min(p,i),max(j,p+j-i),0,n+1)) % mod;
dp[now][i][j][tp] = (dp[now][i][j][tp] + 1ll * dp[pre][i][j][tp] * Sum) % mod;
}
}
int ans = 0;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
ans = (ans+dp[pre][i][j][1]) % mod;
printf("%lld\n",(1ll*ans*Pow(Pow(n*(n+1)/2,mod-2),K)%mod+mod)%mod);
}
标程代码:
#include <bits/stdc++.h>
#define For(i, j, k) for (int i = j; i <= k; i++)
#define Forr(i, j, k) for (int i = j; i >= k; i--)
using namespace std;
const int N = 510;
const int Mod = 1e9 + 7;
typedef long long LL;
LL Pow(LL x, int e) {
LL ret = 1;
while (e) {
if (e & 1) ret = ret * x % Mod;
x = x * x % Mod;
e >>= 1;
}
return ret;
}
LL dp[N][N];
LL A[N][N], B[N][N], C[N][N];
int n, k;
int P[N];
int C2[N];
int main() {
freopen("inverse.in", "r", stdin);
freopen("inverse.out", "w", stdout);
scanf("%d%d", &n, &k);
For(i, 1, n) scanf("%d", &P[i]);
For(i, 1, n) For(j, i + 1, n) dp[i][j] = P[i] > P[j];
For(i, 1, n) C2[i] = C2[i - 1] + i;
LL inv = Pow(C2[n], Mod - 2);
while (k--) {
For(j, 1, n) {
For(i, 1, j - 1) A[i][j] = A[i - 1][j] + dp[i][j];
For(i, 1, j - 1) (A[i][j] += A[i - 1][j]) %= Mod;
}
Forr(i, n, 1) {
Forr(j, n, i + 1) B[i][j] = B[i][j + 1] + dp[i][j];
Forr(j, n, i + 1) (B[i][j] += B[i][j + 1]) %= Mod;
}
For(j, 0, n - 1) {
For(i, 1, n - j) C[i][j] = C[i - 1][j] + dp[i][i + j];
For(i, 1, n - j) (C[i][j] += C[i - 1][j]) %= Mod;
}
For(i, 1, n) For(j, i + 1, n) {
dp[i][j] *= C2[i - 1] + C2[j - i - 1] + C2[n - j];
dp[i][j] += A[j - 1][j] - A[j - i - 1][j] - A[i - 1][j];
dp[i][j] += B[i][i + 1] - B[i][j + 1] - B[i][n + 2 - j + i];
dp[i][j] += i * (n + 1 - j);
dp[i][j] -= C[n + i - j][j - i] - C[n - j][j - i] - C[i - 1][j - i];
dp[i][j] = (dp[i][j] % Mod + Mod) * inv % Mod;
}
}
LL ans = 0;
For(i, 1, n) For(j, i + 1, n) ans += dp[i][j];
ans %= Mod;
printf("%lld\n", ans);
return 0;
}**