zoukankan      html  css  js  c++  java
  • hdu6021[BestCoder #93] MG loves string

    这场BC实在是有趣啊,T2是个没有什么算法但是细节坑的贪心+分类讨论乱搞,T3反而码起来很顺.
    然后出现了T2过的人没有T3多的现象(T2:20人,T3:30人),而且T2的AC率是惨烈的不到3%
    (我T2读入写挂,思路想挂,推倒重码一次,交了7次才过QAQ)
    最后狂码T3赶在结束之前调出来过了,3题最后都没有被叉也没有fst,捡了个rk9,人品好啊.

    题意

    给出26个字母的一个排列,对一个字符串进行一次变换表示将某个字母变成排列中对应的字母.
    例如zabcdefg....wxy,1表示经过一次变换之后,所有的'a'会变成'z','b'会变成'a','c'会变成'b'...
    一个长度为N的随机串经过若干次变换之后必然得到本身.那么我们可以求出得到本身的最小变换次数.
    长度为N的串有(26^N)个,求这些串的最小变换次数之和.(N<=10^9)

    分析

    给出的置换中,对于某一个字母,它至少变换多少次之后得到自身是已知的.对于某一个随机串,它变换到
    自己的最小步数只和出现过的字母种类有关,对出现过的字母变换到自身的最小步数求lcm即可.那么我们
    对出现过的字母种类进行状压,用(f[i][S])表示前i个字母中出现的字母集合为S的方案数.那么(f[i-1][])
    (f[i][])的转移是可以看作矩阵乘法形式的,于是我们可以在(2^{26}logN)的时间内解决暴力.
    仔细分析.如果某个字母变换到自己的最小次数是3,那么它位于一个长度为3的循环中,这3种字母变换到自己
    的最小步数是相同的,因此可以在状态压缩的时候视为一种.如果两个字母处在不同的循环但是长度相同,例如
    "badc....",'a,'b','c','d'的最小步数均为2,也可以视为一种.那么长度为26的串里最多出现6种不同的
    循环长度,我们就可以在(O(2^6logN))内解决.也可以dfs枚举出所有可行的lcm,数量不会比2^6多.

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<map>
    using namespace std;
    const int mod=1000000007;
    int sz;
    struct matrix{
      int a[130][130];
      matrix(){
        memset(a,0,sizeof(a));
      }
      matrix(int x){
        memset(a,0,sizeof(a));
        for(int i=0;i<130;++i){
          a[i][i]=x;
        }
      }
      matrix operator *(const matrix &B)const{
        matrix C;
        for(int i=1;i<=sz;++i){
          for(int j=1;j<=sz;++j){
        for(int k=1;k<=sz;++k){
          C.a[i][k]=(C.a[i][k]+a[i][j]*1ll*B.a[j][k])%mod;
        }
          }
        }
        return C;
      }
    };
    matrix qpow(matrix A,int x){
      matrix ans(1);
      for(;x;x>>=1,A=A*A){
        if(x&1)ans=ans*A;
      }
      return ans;
    }
    char buf[30];
    int a[30];
    int vis[30],T;
    int w[30];
    int b[30];int tot=0;
    int lcm[1024];int totlcm=0;
    int gcd(int a,int b){
      return b==0?a:gcd(b,a%b);
    }
    int LCM(int a,int b){
      return a/gcd(a,b)*b;
    }
    void dfs(int x,int tmp){
      if(x==tot+1){
        lcm[++totlcm]=tmp;
        return;
      }else{
        dfs(x+1,tmp);
        dfs(x+1,LCM(tmp,b[x]));
      }
    }
    matrix A,ANS;
    int main(){
      int tests;scanf("%d",&tests);
      while(tests--){
        tot=0;
        int n;scanf("%d",&n);
        scanf("%s",buf+1);
        for(int i=1;i<=26;++i){
          a[i]=buf[i]-'a'+1;
        }
        ++T;
        for(int i=1;i<=26;++i){
          if(vis[i]!=T){
        int cnt=0;
        for(int j=i;vis[j]!=T;j=a[j]){
          cnt++;vis[j]=T;
        }
        b[++tot]=cnt;
        w[i]=cnt;
        for(int j=a[i];j!=i;j=a[j]){
          w[j]=cnt;
        }
          }
        }
        sort(b+1,b+tot+1);
        int sum=0;
        for(int i=1;i<=tot;++i){
          if(b[i]!=b[i-1]){
        b[++sum]=b[i];
          }
        }
        tot=sum;
        totlcm=0;
        dfs(1,1);
        sort(lcm+1,lcm+totlcm+1);
        sum=0;
        for(int i=1;i<=totlcm;++i){
          if(lcm[i]!=lcm[i-1])lcm[++sum]=lcm[i];
        }
        totlcm=sum;
        A=matrix(0);
        map<int,int> dict;
        for(int i=1;i<=totlcm;++i)dict[lcm[i]]=i;
        for(int i=1;i<=totlcm;++i){
          for(int j=1;j<=26;++j){
        A.a[i][dict[LCM(lcm[i],w[j])]]++;//printf("%d %d
    ",i,dict[LCM(lcm[i],w[j])]);
          }
        }sz=totlcm;
        ANS=qpow(A,n);
        int ans=0;
        for(int i=1;i<=totlcm;++i){
          ans=(ans+lcm[i]*1ll*ANS.a[1][i])%mod;
        }
        printf("%d
    ",ans);
        //    for(int i=1;i<=totlcm;++i)printf("%d ",lcm[i]);printf("
    ");
        //    for(int i=1;i<=tot;++i)printf("%d ",b[i]);printf("
    ");
      }
      return 0;
    }
    
  • 相关阅读:
    angularJs项目实战!02:前端的页面分解与组装
    angularJs项目实战!01:模块划分和目录组织
    django admin 导出数据简单示例
    django 学习之model操作(想细化)
    6.11大杂烩。。
    InlineModelAdmin对象的学习
    django-salmonella的使用
    python 保留两位小数
    Django 时间与时区设置问题
    Django学习
  • 原文地址:https://www.cnblogs.com/liu-runda/p/6660917.html
Copyright © 2011-2022 走看看