题意是说有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;
}