MG loves string

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 131    Accepted Submission(s):
50

Problem Description
MG is a busy boy. And today he's burying himself in
such a problem:

For a length of N , a random string made of lowercase letters, every time when it transforms, all
the character i will turn into a[i] .

MG states that the a[i] consists of a permutation .

Now MG wants to know the expected steps the
random string transforms to its own.

It's obvious that the expected steps
X will be a decimal number.
You should output X∗26Nmod 1000000007 .

 
Input
The first line is an integer T which indicates the case number.(1<=T<=10 )

And as for each case, there are 1 integer  in the first line which indicate the length of random string(1<=N<=1000000000 ).

Then there are 26 lowercase letters a[i] in the next line.

 
Output
As for each case, you need to output a single
line.

It's obvious that the expected steps X will be a decimal number.
You should output X∗26Nmod 1000000007 .

 
Sample Input
2
2
abcdefghijklmnpqrstuvwxyzo
1
abcdefghijklmnopqrstuvwxyz
 
Sample Output
5956
26
 
题意:给定26个小写字母x1,x2,...,x26的字符串作为“密码表”,26个密码分别对应a~z26个小写字母,一个字母进行一次变换,意味着该字母变换成对应的密码,譬如字母b下一次变换应该变成x2,字母x2会变换成x2对应的密码等等(可以知道,经过有限次的变换,每个字母最终还是会变换回来的)。
现在给定一个随机字符串的长度N,并且字符串是由任意的小写字母组成,且该字符串经过有限次变换还是会变换到自身,求任意字符串的变换期望次数。
思路:求期望次数,首先想到的是穷举每一种长度为N的小写字符串(一共26^N种可能),对于每次得到的字符串,求出变换到自身的变换次数,之后求平均。当然这样的效率是极其低下的。每个字母经过有限次变换都是可以变换到自身的,将这个过程中所有经过变换得到的字母组成一个圈,那么这个圈中每一个字母都会变换相同的次数之后变换到自身),这样一来,所有的26个字母就可以被挑拣成几个不同的圈,情况最坏的时候每个字母分别成为一个圈,一共26个圈,有点多,现在继续考虑能否将长度一样的圈挑出来成为一个group,那么这样一共会有多少group呢,最坏的情况,圈的长度从1开始变化,1+2+3+4+5+6+7=28>26,也就是说绝对不可能产生七个长度不同的group,最多6个,这么一来范围就小多了。
现在考虑长度相同的每一个group的性质,可以知道每一个group中的每个字母变换到自身的次数都相同。
那么现在长度为N的随机字符串的每一个位置,都可以由用每一个group中任意一个字符来填充。穷举group的组合情况,对于每一种group的组合情况,随机字符串中的每一位都由这些group中的字符来填充(因为每一个group都至少得派出一个字符来填充随机字符串,所以每一种group的组合情况中group的数量必须小于等于随机串长度N,否则直接排除在这种group的组合),那么由这些group中的字符组成随机串对期望变换次数的贡献=这些group构成的字符串的变换次数change_time*这些group构成的字符串的数量number/(26^N);
其中,change_time=组合中每一个group长度的最小公倍。
p=number/(26^N)则可以由容斥原理得到,举个简单的例子,设Pabc=长度为n的随机串用group a,b,c或其一或其二中字母组成的概率,显然Pabc=((size(a)+size(b)+size(c))/26)^N.那么随机串由group a,b,c组成的概率P=Pabc-Pab-Pac-Pbc+pa+pb+pc;
穷举group的组合情况并累加贡献即可得到最终期望。
AC代码:

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<algorithm>
#include<string>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
const int N_MAX = + ,INF= ;
int N;
string s;
vector<pair<int,int> >loop;//圈的大小<->圈的个数 ll gcd(ll a,ll b) {
if (b == )return a;
return gcd(b, a%b);
} ll lcm(ll a,ll b) {
return a / gcd(a, b)*b;
} void cal_loop() {
loop.clear();
int change[],vis[];
memset(vis,,sizeof(vis));
for (int i = ; i < s.size();i++) {
change[i] = s[i] - 'a';
}
map<int, int>m;
for (int i = ; i < ;i++) { if (vis[i])continue;
vis[i] = true;
int num = ;
int k = change[i];//k代表不断变化的字母
while (i != k) {
vis[k] = true;
num++;//该圈的元素个数加1
k = change[k];//!!!!!顺序
}
m[num]++;
}
for (map<int, int>::iterator it = m.begin(); it != m.end();it++) {
loop.push_back(*it);
}
} ll mod_pow(ll x,ll n) {//快速幂运算
ll res = ;
while (n>) {
if (n & )res = res*x%INF;
x = x*x%INF;
n >>= ;
}
return res;
} ll R_C(vector<int>&loop,int N) {//容斥原理,求由这些圈中的元素组成的长度为N的字符串的数量
ll permute = << (loop.size());
ll ans = ;
for (int i = ; i < permute;i++) {
int num = ;
int sum = ;
int sign=-;
for (int j = ; j < loop.size(); j++) {
if (i&( << j)) {
num++;//num记录利用到的圈的个数
sum += loop[j];//利用到的字符的总个数
}
}
if (num % == loop.size() % )//!!!!!!!!
sign = ;
ans =(ans+((sign*mod_pow(sum, N))%INF+INF)%INF)%INF;
}
return ans;
} ll solve(int N) {
cal_loop();
vector<int>vec;
ll ans = ;
for (int i = ; i < (<<loop.size());i++) {
ll change_time=;
vec.clear();
for (int j = ; j < loop.size();j++) {
if (i&( << j)) {
vec.push_back(loop[j].first*loop[j].second);
change_time = lcm(change_time, loop[j].first);
}
}
if (vec.size() > N)continue;//挑选出来的圈的个数不能超过字符串长度
ll number = R_C(vec, N);
ans = (ans + change_time*number) % INF;
}
return ans;
} int main() {
int T;
scanf("%d",&T);
while (T--) {
scanf("%d",&N);
cin >> s;
printf("%lld\n",solve(N));
}
return ;
}

hdu 6021 MG loves string的更多相关文章

  1. hdu 6021 MG loves string (一道容斥原理神题)(转)

    MG loves string    Accepts: 30    Submissions: 67  Time Limit: 2000/1000 MS (Java/Others)    Memory ...

  2. ●HDU 6021 MG loves string

    题链: http://acm.hdu.edu.cn/showproblem.php?pid=6021 题解: 题意:对于一个长度为 N的由小写英文字母构成的随机字符串,当它进行一次变换,所有字符 i ...

  3. 【HDU 6021】 MG loves string (枚举+容斥原理)

    MG loves string  Accepts: 30  Submissions: 67  Time Limit: 2000/1000 MS (Java/Others)  Memory Limit: ...

  4. MG loves string

    MG loves string Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others ...

  5. hdu 6020 MG loves apple 恶心模拟

    题目链接:点击传送 MG loves apple Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 262144/262144 K (Ja ...

  6. hdu6021[BestCoder #93] MG loves string

    这场BC实在是有趣啊,T2是个没有什么算法但是细节坑的贪心+分类讨论乱搞,T3反而码起来很顺. 然后出现了T2过的人没有T3多的现象(T2:20人,T3:30人),而且T2的AC率是惨烈的不到3% ( ...

  7. 【HDU 6020】 MG loves apple (乱搞?)

    MG loves apple  Accepts: 20  Submissions: 693  Time Limit: 3000/1500 MS (Java/Others)  Memory Limit: ...

  8. best corder MG loves gold

    MG loves gold  Accepts: 451  Submissions: 1382  Time Limit: 3000/1500 MS (Java/Others)  Memory Limit ...

  9. Hdu 5806 NanoApe Loves Sequence Ⅱ(双指针) (C++,Java)

    Hdu 5806 NanoApe Loves Sequence Ⅱ(双指针) Hdu 5806 题意:给出一个数组,求区间第k大的数大于等于m的区间个数 #include<queue> # ...

随机推荐

  1. alibaba druid监控页面的使用配置

    一.Maven中添加Durid连接池依赖 <!-- druid连接池 --> <dependency> <groupId>com.alibaba</group ...

  2. 接口的多态使用; 接口应用实例:U盘、打印机可以使用共同的USB接口,插入到电脑上实现各自的功能。

    接口的多态使用 接口应用实例:U盘.打印机可以使用共同的USB接口,插入到电脑上实现各自的功能.

  3. C++ 学习笔记(四)类的内存分配及this指针

    类,是使用C++的最主要的内容.如果将c++与C语言做比较,我感觉类更像是结构体的加强进化版.在刚接触C++不久的时候总是让类,对象,this指针弄得一脸懵逼,我对类有比较清楚的认识是从理解类在内存中 ...

  4. Ubuntu下搭建多用户多权限ftp

    #1.切换root用户模式 (已在root模式下的请忽略) sudo -i #然后提示你输入当前用户密码,输入密码后回车后如果密码正确控制台就变成root@***:/# 了. #2.更新软件源 apt ...

  5. Relu的缺点

    Relu不适合梯度过大的的输入 Relu是我们在训练网络时常用的激活函数之一(对我而言没有之一).然而最近发现Relu太脆弱了,经常由于输入的函数梯度过大导致网络参数更新后,神经元不再有激活功能.特别 ...

  6. Python之路-时间模块

    time模块 import time 时间戳(time.time())--结构化时间(time.localtime)--字符串时间(time.strftime) import time print(t ...

  7. OpenCV中的图像形态学转换

    两个基本的形态学操作是腐蚀和膨胀.他们的变化构成了开运算,闭运算,梯度等.下面以这张图为例 1.腐蚀 这个操作会把前景物体的边界腐蚀掉. import cv2 import numpy as np i ...

  8. build_mem_type_table

    该函数设置mem_types结构体数组,结构体定义如下: struct mem_type { unsigned int prot_pte;     //二级页表属性 unsigned int prot ...

  9. zoj 4049

    Halting Problem Time Limit: 1 Second      Memory Limit: 65536 KB In computability theory, the haltin ...

  10. Linux网络编程:客户端/服务器的简单实现

    一. Socket的基本知识 1. socket功能 Socket层次 Socket实质上提供了进程通信的端点,进程通信之前,双方必须首先各自创建一个端点,否则是没有办法建立联系并相互通信的. 每一个 ...