1. 程式人生 > >hdu 6021 MG loves string

hdu 6021 MG loves string

define clas group itl step accep 進行 algo ati

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 = 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