• ●HDU 6021 MG loves string


    题链:

    http://acm.hdu.edu.cn/showproblem.php?pid=6021

    题解:

    题意:
    对于一个长度为 N的由小写英文字母构成的随机字符串,
    当它进行一次变换,所有字符 i 都会变成a[i]。
    同时变换数组:a[i]是26个字母组成的排列。
    现在需要知道这个随机串变换到自身的期望变换次数。
    请你输出期望答案乘上26^N以后模 1000000007的结果。


    容斥,LCM
    其实题目要求的就是每种串(共有 26^N种串)回到自身的变化次数之和。


    暴力求法就是:
    看每种串的每个字符在循环长度为多少的循环里(设第i个位置的字符的循环长度为 Di),
    则该串的变化次数为 LCM(D1,D2,D3...,DN)(最小公倍数)


    不难发现,对于给定的变化数组 a[ ],循环长度不同的循环节的种类个数不超过 6 个(1+2+3+4+5+6+7>26)
    6很小,所以就可以在这个 "6" 上面搞事情。


    枚举循环节的集合 S,表示串里的字符只能是这些循环节的字母集合里的字母
    就是把 N 个字符放到那些循环节的字母集合中去。
    (假设这个集合的循环节只包含了 W 个字母)
    但是我们要使得串的变化次数为 LCM(Di, ${i}epsilon{S}$ ),(即答案为这些循环节长度的 LCM)
    那么每个循环节里面都至少要有一个字符被在里面。
    所以问题转化为:N个东西分到 M 个盒子,每个盒子都至少有一个东西。
    求法如下:
    设 f[S] 表示在 S集合的循环节里随便放的方案数,即每个字符可以随便选择 W 个字母里面的任意一个。
    显然 f[S] = $W^N$。但是这个 f[S] 有非法方案,即存在某些循环节里没有放字符。
    所以容斥如下:
    ANS = 没有涵盖至少 0个循环节的方案数(即f[S])
              -没有涵盖至少 1个循环节的方案数
              +没有涵盖至少 2个循环节的方案数
              -...+... 
    用于容斥的方案数就直接枚举 S 的子集 _S,(方案数即为 f[_S])。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define _ % mod
    #define filein(x) freopen(#x".in","r",stdin);
    #define fileout(x) freopen(#x".out","w",stdout);
    using namespace std;
    const int mod=1000000007;
    int f[100],vis[100],d[100],g[100],h[100],tot;;
    char S[100];
    int T,N,ANS;
    int gcd(int a,int b){
    	while(b^=a^=b^=a%=b);
    	return a;
    }
    int pow(int a,int b){
    	int now=1;
    	while(b){
    		if(b&1) now=(1ll*now*a)_;
    		a=(1ll*a*a)_; b>>=1;
    	}
    	return now;
    }
    void precircle(){
    	tot=0;
    	scanf("%d",&N);
    	scanf("%s",S+1);
    	memset(d,0,sizeof(d)); 
    	memset(h,0,sizeof(h)); 
    	memset(vis,0,sizeof(vis)); 
    	for(int i=1;i<=26;i++) 
    		if(!vis[S[i]-'a'+1]){
    		int tmp=0,p=S[i]-'a'+1;
    		while(!vis[p]) tmp++,vis[p]=1,p=S[p]-'a'+1;
    		d[tmp]++;
    	}
    	for(int i=1;i<=26;i++) 
    		if(d[i]) tot++,g[tot]=d[i],d[tot]=i;
    	for(int s=1,cnt;cnt=0,s<(1<<tot);s++){
    		for(int i=1;i<=tot;i++) 
    			if(s&(1<<(i-1))) 
    				cnt+=g[i]*d[i],h[s]++;
    		f[s]=pow(cnt,N);
    	}
    	/*for(int s=1,tmp;s<(1<<tot);s++){
    		for(int _s=s;_s;_s=(_s-1)&s){
    			if(s==_s) continue;
    			tmp=-f[_s];
    			tmp=(1ll*tmp+mod)_;
    			f[s]=(1ll*f[s]+tmp+mod)_;
    		}
    	}正推就不用容斥了*/
    	for(int s=1,tmp;s<(1<<tot);s++){
            for(int _s=s;_s;_s=(_s-1)&s){
                if(s==_s) continue;
                tmp=-f[_s];
                tmp=(1ll*tmp+mod)_;
                f[s]=(1ll*f[s]+tmp+mod)_;
            }
        }//逆推需要容斥 
    }
    void dfs(int p,int s,int lcm){
    	if(p==tot+1){
    		ANS=(1ll*ANS+(1ll*f[s]*lcm)_)_;
    		return;
    	}
    	dfs(p+1,s,lcm);
    	dfs(p+1,s|(1<<(p-1)),1ll*lcm/gcd(lcm,d[p])*d[p]);
    }
    int main()
    {
    	scanf("%d",&T);
    	while(T--){
    		ANS=0;
    		precircle();
    		dfs(1,0,1);
    		printf("%d
    ",ANS);
    	}
    	return 0;
    }
    

  • 相关阅读:
    环境变量
    查看进程的环境变量
    shell打印彩色输出
    python使用smtplib发送邮件
    多线程实现ping扫描
    python ssh之paramiko模块使用
    Windows环境安装tesseract-ocr 4.00并配置环境变量
    Scrapy教程,亲测能用
    pycharm 调试 scrapy
    Python中元组,列表,字典的区别
  • 原文地址:https://www.cnblogs.com/zj75211/p/8035023.html
Copyright © 2020-2023  润新知