HDU-3461 Code Lock 並查集 + 二分求冪

___Evan發表於2014-01-24

題目連結

題意是說有N個字母組成的密碼鎖, 如【wersdfj】,   每一位上的字母可以轉動, w可轉動變成x, z變成a。但是題目規定, 只能同時轉動某個區間上的所有字母, 如【1,3】, 那麼第1到第3個的所有字母要同時轉動,那麼【 wersdfj 】經過一次操作就變成 【 xfssdfj 】.    一共有M 個區間是可以操作的。  

題目還規定:If a lock can change to another after a sequence of operations, we regard them as same lock. 

就是說, 經過可操作區間進行的操作得到的所有鎖情況,都是同一個的。 也就是說,所有不同的鎖就是“不可操作區間”的所有組合情況。


在最初時,每個字母看作是一個獨立的區間, 那麼就有N個區間, 可以很容易地用初始化的並查集來表示。然後一個區間可以看作是一個“元素”,  我們只需要求出共有多少個可操作區間x, 然後就可以計算得到N-x個不可操作的區間。 不可操作區間的所有組合,就是能組成的所有不同的鎖。

每個區間可以有26種情況, 那麼就共有26^(N-x)種情況。由於N可能會很大,所以直接計算浪費時間了,用二分求冪法來計算出結果。


#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
using namespace std;
const int maxn = 10000005;
const int inf = 1<<30;
const __int64 MOD = 1000000007;
int n,m,ans;
int p[maxn];
int find(int x)  
{  
    return x!=p[x]?p[x]=find(p[x]):x;  
} 
void merge( int a,int b )
{
	int x = find(a);
	int y = find(b);
	if( x != y ){
		p[x] = y;
		ans ++;
	}
}
void init()
{
	ans = 0;
	for( int i = 0; i <= n; i ++ )
		p[i] = i;
}
__int64 fun( int x )
{
	__int64 sum = 1,tmp = 26;
	while( x ){
		if( x&1 ){
			sum = sum * tmp;
			sum %= MOD;
		}
		tmp = (tmp*tmp)%MOD;
		x >>= 1;
	}
	return sum;
}
int main()
{
    //freopen("data.txt","r",stdin);   
	int l,r;
	while( scanf("%d%d",&n,&m) != EOF ){
		init();
		for( int i = 0; i < m; i ++ ){
			scanf("%d%d",&l,&r);
			merge( l-1,r );
		}
		printf("%I64d\n",fun(n-ans)%MOD);
	}
    return 0;
}


相關文章