hdu 6021 MG loves string
阿新 • • 發佈:2017-05-15
define clas group itl step accep 進行 algo ati
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 .
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.
It‘s obvious that the expected steps X will be a decimal number.
You should output X?26Nmod 1000000007 .
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
For a length of N
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
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
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 = 1000000000 + 2,INF= 1000000007; int N; string s; vector<pair<int,int> >loop;//圈的大小<->圈的個數 ll gcd(ll a,ll b) { if (b == 0)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[26],vis[26]; memset(vis,0,sizeof(vis)); for (int i = 0; i < s.size();i++) { change[i] = s[i] - ‘a‘; } map<int, int>m; for (int i = 0; i < 26;i++) { if (vis[i])continue; vis[i] = true; int num = 1; 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 = 1; while (n>0) { if (n & 1)res = res*x%INF; x = x*x%INF; n >>= 1; } return res; } ll R_C(vector<int>&loop,int N) {//容斥原理,求由這些圈中的元素組成的長度為N的字符串的數量 ll permute = 1 << (loop.size()); ll ans = 0; for (int i = 0; i < permute;i++) { int num = 0; int sum = 0; int sign=-1; for (int j = 0; j < loop.size(); j++) { if (i&(1 << j)) { num++;//num記錄利用到的圈的個數 sum += loop[j];//利用到的字符的總個數 } } if (num % 2 == loop.size() % 2)//!!!!!!!! sign = 1; ans =(ans+((sign*mod_pow(sum, N))%INF+INF)%INF)%INF; } return ans; } ll solve(int N) { cal_loop(); vector<int>vec; ll ans = 0; for (int i = 0; i < (1<<loop.size());i++) { ll change_time=1; vec.clear(); for (int j = 0; j < loop.size();j++) { if (i&(1 << 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 0; }
hdu 6021 MG loves string