[BalticOI 2012] 旋律 (Day2)
构史题目,加个构造到底是何意味。
容易发现一个图论建模,每一个位置都建出 \(n\) 个点代表这个位置选这个音符。依据合法性可以连边,跑最短路。但是边数有 \(10^9\),是难以通过的。
由于一层只会向下一层连边,可以考虑 DP,设 \(f_{i,j}\) 表示第 \(i\) 个位置选 \(j\) 时最小要更改的音符数量,转移是平凡的,时间复杂度 \(O(Ln^2)\),不可通过。
考虑换一种角度,设 \(f_i\) 为 \(i\) 位置填对时前 \(i\) 个位置的最大的不变音符数量,答案为 \(L-\max_{i=1}^l f_i\),看似没有约束后面的位置,相当于直接后面全填 \(a_i\),但如果后面某处填 \(a_i\) 是对的,那 \(f_i\) 一定不会被取到,显然后面更优。
要先做一次 floyd,得到 \(dis_{i,j}\) 表示从 \(i\) 到 \(j\) 至少需要几个位置,则转移为 \(f_{i} = 1+\max_{j<i,dis_{i,j}\le i-j} f_j\)。直接做是 \(O(L^2)\) 的。
发现,条件里的 \(dis_{i,j}\le i-j\),可以变成 \(j+f_{i,j} \le i\),则 \(f_j\) 能生效的位置,一定是在 \(j+f_{j,v}\) 之后,令 \(g_{i,v}\) 表示第 \(i\) 层被提前转移好的最大值,\(f_i\) 直接取 \(g_{i,a_i}\) 就行了。
构造部分不想写了。
时间复杂度 \(O(Ln+n^3)\),可以通过。
#include<bits/stdc++.h>
using namespace std;
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
#define endl '\n'
int n,m,k,l;
const int N = 105,M=1e5+10,inf=1e9;
string s[N];
bitset<N>vis[N];
int a[M],dis[N][N],nxt[N][N],f[M],g[M][N],lst[M][N],pre[M];
int p[M];
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m>>k;
for(int i=1;i<=n;i++){
cin>>s[i];
vis[i][i]=1;
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
int cnt=0;
for(int k=0;k<m;k++){
cnt+=(s[i][k]==s[j][k]);
}
if(cnt>=m-k)vis[i][j]=vis[j][i]=1;
}
}
cin>>l;
for(int i=1;i<=l;i++){
cin>>a[i];
}
memset(dis,0x3f,sizeof(dis));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(vis[i][j]){
dis[i][j]=1;
nxt[i][j]=j;
}
}
}
for(int i=1;i<=n;i++)dis[i][i]=0,nxt[i][i]=i;
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(dis[i][j]>dis[i][k]+dis[k][j]){
dis[i][j]=dis[i][k]+dis[k][j];
nxt[i][j]=nxt[i][k];
}
}
}
}
for(int i=1;i<=l;i++){
for(int v=1;v<=n;v++){
if(g[i][v]<g[i-1][v]){
g[i][v]=g[i-1][v];
lst[i][v]=lst[i-1][v];
}
}
f[i]=g[i][a[i]]+1;
pre[i]=lst[i][a[i]];
for(int v=1;v<=n;v++){
int t=i+dis[a[i]][v];
if(t<=l){
if(f[i]>g[t][v]){
g[t][v]=f[i];
lst[t][v]=i;
}
}
}
}
int ans=0,id=0;
for(int i=1;i<=l;i++){
if(f[i]>ans){
ans=f[i];
id=i;
}
}
cout<<l-ans<<endl;
vector<int>v;
while(id){
v.push_back(id);
id=pre[id];
}
reverse(v.begin(),v.end());
for(int i=1;i<=v[0];i++){
p[i]=a[v[0]];
}
for(int i=1;i<v.size();i++){
int x=v[i-1],y=v[i];
int d=dis[a[x]][a[y]];
for(int j=x+1;j<=y-d;j++){
p[j]=a[x];
}
int u=a[x];
for(int j=y-d+1;j<=y;j++){
u=nxt[u][a[y]];
p[j]=u;
}
}
int pos=v.back();
for(int i=pos+1;i<=l;i++)p[i]=a[pos];
for(int i=1;i<=l;i++)cout<<p[i]<<" ";
return 0;
}

浙公网安备 33010602011771号