[BalticOI 2012] 旋律 (Day2)

[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;
}
posted @ 2026-10-21 21:04  farenara_sayowell  阅读(3)  评论(0)    收藏  举报