AtCoder Regular Contest 213 Div1 部分题目题解

比赛传送门:AtCoder Regular Contest 213 Div1

没打,赛后来看看题。

A 题解

首先长度为 \(L\) 的排列 \(a\) 变成 \(1,2,3,\cdots L\) 只能交换相邻位置的最少次数为 \(a\)逆序对数量,那么设 \(W(a,b)\) 表示 \(a\) 只能交换相邻位置到 \(b\) 的最少次数,可以 \(O(L^2)\) 轻松求出。

\(f_i\) 表示已第 \(i\) 个排列结尾的最大代价。

\[f_i = \max_{j<i,W(p_j,p_i)\le j-i} \{f_j+c_i\} \]

直接做是 \(O(n^2L^2)\) 的,考虑优化,容易发现一个长度为 \(L\) 的排列 \(a\) 最多只需要操作 \(O(L^2)\) 次就可以变成 \(b\),因此转移时 \(j\in [i-L^2,i-1]\) 这部分判断,剩下的位置全部满足条件,用个前缀最大值即可,这样复杂度即为 \(O(nL^4)\)

#include<bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
inline int read(){
	char c=getchar();
	int f=1,ans=0;
	while(c<48||c>57) f=(c==45?f=-1:1),c=getchar();
	while(c>=48&&c<=57) ans=(ans<<1)+(ans<<3)+(c^48),c=getchar();
	return ans*f;
}
const int N=3e4+10,M=15;
int n,l,p[N][M],c[N],f[N],mp[M],g[N];
inline int get(int x,int y){
	int ans=0;
	for (int i=1;i<=l;i++) mp[p[y][i]]=i;
	for (int i=1;i<=l;i++) for (int j=i+1;j<=l;j++) if (mp[p[x][i]]>mp[p[x][j]]) ans++;
	return ans;
}
main(){
	n=read(),l=read();
	for (int i=1;i<=l;i++) p[0][i]=i;
	for (int i=1;i<=n;i++){
		c[i]=read();
		for (int j=1;j<=l;j++) p[i][j]=read();
	} 
	memset(f,-0x3f,sizeof(f)),f[0]=0;
	for (int i=1;i<=n;i++){
		for (int j=max(0ll,i-l*l);j<i;j++) if (get(i,j)<=i-j) f[i]=max(f[i],f[j]+c[i]);
		if (i-l*l-1>=0) f[i]=max(f[i],g[i-l*l-1]+c[i]);
		g[i]=max(g[i-1],f[i]);
	}
	cout <<g[n];
    return 0;
}
posted @ 2026-01-28 16:11  OTn53_qwq  阅读(8)  评论(0)    收藏  举报