hdu 6021 MG loves string (一道容斥原理神題)(轉)
阿新 • • 發佈:2018-12-17
MG loves string Accepts: 30 Submissions: 67 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others) 問題描述 MGMG是一個很忙碌的男孩子。今天他沉迷於這樣一個問題:
對於一個長度為NN的由小寫英文字母構成的隨機字串,當它進行一次變換,所有字元ii都會變成a[i]a[i]。
MGMG規定所有a[i]a[i]構成了2626個字母組成的排列。
MGMG現在需要知道這個隨機串變換到自身的期望變換次數。請你輸出期望答案乘上26^n26 n 以後模 10000000071000000007 的結果。
MGMG認為這件事非常容易,不屑於用計算機解決,於是運用他高超的人類智慧開始進行計算。作為一名旁觀者,你也想挑戰MGMG智慧,請你寫個程式,計算答案。 輸入描述 第一行一個整數TT,代表資料組數(1 <=T<=101<=T<=10)。
接下來,對於每組資料——
第一行一個整數NN,表示給定的隨機串長度(1<=N<=10000000001<=N<=1000000000)。
第二行2626個字母,表示a_ia i 序列 輸出描述 對於每一組資料,輸出一行。
顯然,這個期望是一個實數。請你輸出它乘上26^N26 N 以後模 10000000071000000007 的結果 輸入樣例 2 2 abcdefghijklmnpqrstuvwxyzo 1 abcdefghijklmnopqrstuvwxyz 輸出樣例 5956 26
題解請參考這位大神:
他的程式碼:
#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("in.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; }