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

浙公网安备 33010602011771号