• BZOJ4607 : [PA2015 Final]Edycja


    显然做完操作$2$后再做操作$1$。

    建立一个$26$个点的有向图,每个点只有一条出边,$i$->$j$表示$i$最终变成了$j$,边权为一开始是$i$,最后不是$j$的位置个数,如果$i eq j$,则代价还要增加$c$。

    对于每个点贪心选取最小的出边,如果没有环,那么此时就是最优解。

    否则,对于一个连通块,如果它是环,那么需要多付出$c$点代价,而且如果所有连通块都是环或者孤立点,则不可能构造出这种图。

    考虑重新决定每个点的出边,如果出现了原来贪心构造出的图中不存在的环,那么一定有一个点的出边和一开始不同,因为一开始是贪心选最小,因此把那条边改回最开始的出边,答案不会增加,而且新环被破坏了。因此对于不是原来中的图的环,一定存在一种方案与它代价相同,且不存在这个环。

    于是设$f[i][S][j]$表示考虑了前$i$个字符,$S$集合的环已经被破坏,是否和原图一样为$j$时边权的最小值,DP即可。

    因为最多只有$13$个环,所以时间复杂度为$O(n+26^2 imes2^{13})$。

    #include<cstdio>
    const int N=26,M=1000010,inf=~0U>>1;
    int n,c,m,flag,i,j,k,S,U,v[N][N],ap[N],w[N][N],g[N],fa[N],d[N],vis[N],del[N],id[N];
    int f[N+1][1<<(N/2)][2],ans;char a[M],b[M];
    int F(int x){return fa[x]==x?x:fa[x]=F(fa[x]);}
    inline void up(int&a,int b){if(a>b)a=b;}
    int main(){
      scanf("%d%d%s%s",&n,&c,a,b);
      for(i=0;i<n;i++)v[a[i]-'a'][b[i]-'a']++,ap[a[i]-'a']++;
      for(i=0;i<N;i++)for(j=0;j<N;j++){
        w[i][j]=ap[i]-v[i][j];
        if(i!=j)w[i][j]+=c;
      }
      for(i=0;i<N;i++)fa[i]=i,id[i]=-1;
      for(i=0;i<N;i++){
        for(k=j=0;j<N;j++)if(w[i][j]<w[i][k])k=j;
        d[g[i]=k]++;
        if(F(i)!=F(k))fa[fa[i]]=fa[k];
      }
      for(i=0;i<N;i++)if(!del[F(i)]){
        del[fa[i]]=vis[i]=1;
        for(j=g[i];!vis[j];j=g[j])vis[j]=1;
        if(g[j]==j)continue;
        for(id[j]=m,k=g[j];k!=j;k=g[k])id[k]=m;
        m++;
      }
      if(!m){
        for(i=0;i<N;i++)ans+=w[i][g[i]];
        return printf("%d",ans),0;
      }
      for(flag=1,i=0;i<N;i++)if(d[i]!=1)flag=0;
      for(i=0;i<=N;i++)for(S=0;S<1<<m;S++)for(j=0;j<2;j++)f[i][S][j]=inf;
      f[0][0][0]=0;
      for(i=0;i<N;i++)for(S=0;S<1<<m;S++)for(j=0;j<2;j++)if(f[i][S][j]<inf)for(k=0;k<N;k++){
        U=S;
        if(~id[i]&&k!=g[i])U|=1<<id[i];
        if(~id[k]&&(k!=g[i]||id[i]!=id[k]))U|=1<<id[k];
        up(f[i+1][U][j||k!=g[i]],f[i][S][j]+w[i][k]);
      }
      for(ans=inf,S=0;S<1<<m;S++)for(j=flag;j<2;j++)if(f[N][S][j]<inf)up(ans,f[N][S][j]+(m-__builtin_popcount(S))*c);
      return printf("%d",ans),0;
    }
    

      

  • 相关阅读:
    会说话的TOM猫的原理是什么
    ios5 中文键盘高度变高覆盖现有ui问题的解决方案(获取键盘高度的方法)
    HJ2 计算某字母出现次数
    HJ1 字符串最后一个单词的长度
    windows 服务开发和windows install开发
    DICOM简介
    Active Directory 开发
    WF Workflow 状态机工作流 开发
    DICOM Query 和Retrieve 的方法和定义
    步步为营UML建模系列七、表图(Data model diagram)
  • 原文地址:https://www.cnblogs.com/clrs97/p/5545772.html
Copyright © 2020-2023  润新知