Code Lock
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)
Total Submission(s): 2043 Accepted Submission(s): 788
At each operation, you are only allowed to move some specific subsequence of contiguous wheels up. This has the same effect of moving each of the wheels up within the subsequence.
If a lock can change to another after a sequence of operations, we regard them as same lock. Find out how many different locks exist?
Each test case begin with two integers N (1<=N<=10000000) and M (0<=M<=1000) indicating the length of the code system and the number of legal operations.
Then M lines follows. Each line contains two integer L and R (1<=L<=R<=N), means an interval [L, R], each time you can choose one interval, move all of the wheels in this interval up.
The input terminates by end of file marker.
Statistic | Submit | Discuss | Note
弱鸡的我很难想到并查集做。(QAQ)
题目大意:一个N长度的字母密码锁,可以任意改变任一字母的值。现在给定M个区间,每次改变,区间内的字母都改变,如果密码锁转动之后结果一样,就看做同一种密码锁,问有多少种不同的密码锁。例如一种密码锁为【abcde】,区间为【1,2】,改变一次则变为【bccde】。
思路:①如果不存在区间,则共有26^N个密码锁。
②如果有一个区间且长度为1,例如【abcde】,区间【1,1】,则第一个字母a可以取任意字母,如果任意锁与该锁后四个字母相同,即相同锁。所以此时共有26^(N-1)个密码锁。
③如果有一个区间长度任意,例如【abcde】,区间【1,3】如果任意锁与该锁后四个字母相同,并且前三个字母ASCII值相对位置相同,即相同锁。所以此时共有26^(N-3)个密码锁。
④对于普通情况,共n个区间,每个区间长度任意,共有26^(N-n)个密码锁。
现在问题出来了,例如【abcde】,区间【1,2】,【3,5】,【1,5】。改变前两个区间和改变第三个区间操作结果是一样的,此时有两种密码锁。
但是对于【1.2】,【2,5】【1,5】则不同,因为2操作重复了一次,此时有三种密码锁。所以合并的时候用(a-1,b)即可)(所以最初初始化从0开始)
这个时候就可以想到并查集了,统计共有sum个联动独立的区间,然后最后得到26^(N-sum)取模运算即可。
WA了一次,因为快速幂应该用long long.
附上AC代码:
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn=10000000+5;
const int mod=1000000007;
int par[maxn];
int sum;
int N,M,L,R;
void init()
{
for(int i=0;i<maxn;i++)
par[i]=i;
sum=0;
}
int find(int a)
{
if(a==par[a])return a;
return par[a]=find(par[a]);
}
void unite(int a,int b)
{
a=find(a);
b=find(b);
if(a==b)return ;
else if(a!=b)
{
sum++;
if(a>b)par[a]=b;
else par[b]=a;
}
}
ll pow_mod(ll a,ll b,int n)
{
if(b==0)return 1;
ll x=pow_mod(a,b/2,n);
ll ans=x*x%n;
if(b%2)ans=ans*a%n;
return ans;
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>N>>M)
{
init();
for(int i=0;i<M;i++)
{
cin>>L>>R;
unite(L-1,R);
}
cout<<pow_mod(26,N-sum,mod)%mod<<endl;
}
return 0;
}