zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

  • 相关阅读:
    Codeforces Beta Round #92 (Div. 2 Only) B. Permutations 模拟
    POJ 3281 Dining 最大流 Dinic算法
    POJ 2441 Arrange the BUlls 状压DP
    URAL 1152 Faise Mirrors 状压DP 简单题
    URAL 1039 Anniversary Party 树形DP 水题
    URAL 1018 Binary Apple Tree 树形DP 好题 经典
    pytorch中的forward前向传播机制
    .data()与.detach()的区别
    Argparse模块
    pytorch代码调试工具
  • 原文地址:https://www.cnblogs.com/clrs97/p/5545772.html
Copyright © 2011-2022 走看看