MG loves string
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 99 Accepted Submission(s): 31
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 N 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
Source
BestCoder Round #93
假设字符串str第i个位置的字母 经过
ai
次变换能变回自身
那str需要
lcm(a0,a1,a2,.......,an−1)
次变换,才能变回自身
显然 从字母
α
变回
α
途径的字母 ,组成一个环
26个字母组成若干个不相交的环
枚举每个环有没有被选择
如果环
c1,c2,...cn
被选择了 那这种状态对答案的贡献
=lcm(c1,c2,....,cn)∗满足这种状态的字符串数量
显然这个数量可以容斥求出:
设
Pabc=长度为n的随机串,只用环a,b,c中的字母构成的概率
Pabc=((size(a)+size(b)+size(c)26)n
由环a,b,c组成的字符串数量=26n∗(Pabc−Pab−Pac−Pbc+Pa+Pb+Pc)
然后….tle
最坏情况下 有26个环 ,
226=67108864
而1+2+3+4+5+6+7=28 > 26,也就是说 大小不一样的环 不会超过6个
而lcm2个相同的数是毫无意义的
如果将相同大小的环合并在一起 , 就可以压缩为
26
然后愉快得ac了….
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<string>
#include<vector>
#include<deque>
#include<queue>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<ctime>
#include<string.h>
#include<math.h>
#include<list>
using namespace std;
#define ll long long
#define pii pair<int,int>
const int inf = 1e9 + 7;
char to[27];
bool vis[27];
vector<pii>loop;//fist 循环节长度为first 有second个循环节长度为first
void calLoop(){
for(int i=0;i<26;++i){
to[i]-='a';
}
map<int,int>mp;
fill(vis,vis+27,0);
loop.clear();
for(int i=0;i<26;++i){
if(vis[i]==0){
vis[i]=1;
int ans=1;
int x=to[i];
while(x!=i){
vis[x]=1;
++ans;
x=to[x];
}
mp[ans]+=1;
}
}
for(auto it=mp.begin();it!=mp.end();++it){
loop.push_back(*it);
}
}
ll lcm(ll a,ll b){
ll tmp=__gcd(a,b);
return a/tmp*b;
}
ll quickMulti(ll a,ll n){
ll ans=1;
ll t=a%inf;
while(n){
if(n&1){
ans=(ans*t)%inf;
}
t=(t*t)%inf;
n>>=1;
}
return ans;
}
inline ll mod(ll x){
return (x%inf+inf)%inf;
}
ll f(vector<int>&vec,int n){//容斥
ll ans=0;
int nv=vec.size();
for(int i=1,end=1<<nv;i<end;++i){
ll flag=-1;
int sum=0,num=0;
for(int j=0;j<nv;++j){
if((1<<j)&i){
sum+=vec[j];
++num;
}
}
if(num%2==nv%2){
flag=1;
}
ll t=quickMulti(sum,n);
ans=(ans+mod(flag*t))%inf;
}
return ans;
}
ll slove(int n){
calLoop();
ll ans=0;
vector<int>vec;//当前选择了的循环节包含的字母数
for(int i=1,end=1<<loop.size();i<end;++i){//枚举循环节的状态
ll ans1=1;//选择了这几个循环节的贡献
vec.clear();
for(int j=0;j<loop.size();++j){
if((1<<j)&i){
ans1=lcm(ans1,loop[j].first);
vec.push_back(loop[j].first*loop[j].second);
}
}
if(vec.size()>n){
continue;
}
ll ans2=f(vec,n);
ans=(ans+ans1*ans2)%inf;
}
return ans;
}
int main()
{
//freopen("/home/lu/Documents/r.txt","r",stdin);
//freopen("/home/lu/Documents/w.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--){
int n;
scanf("%d%s",&n,to);
printf("%lld\n",slove(n));
}
return 0;
}