$Inverse$ Day7 T1

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/86362036

在这里插入图片描述 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 ( n 2 k ) O(n^2k) 但是求和顺序有点奇怪,导致需要5~7类分类讨论吗,无奈只能打了 O ( n 3 k ) O(n^3k) ,而标程交换了求和顺序,代码简洁,边界情况基本没有。。。。。。

我的代码:

#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;
}**

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/86362036
今日推荐