hdu3461 Code Lock(并查集+快速幂)

来源:互联网 发布:软件开发学徒骗局 编辑:程序博客网 时间:2024/05/15 23:50
Code LockTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 2029    Accepted Submission(s): 783Problem DescriptionA lock you use has a code system to be opened instead of a key. The lock contains a sequence of wheels. Each wheel has the 26 letters of the English alphabet 'a' through 'z', in order. If you move a wheel up, the letter it shows changes to the next letter in the English alphabet (if it was showing the last letter 'z', then it changes to 'a').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?InputThere are several test cases in the input.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.OutputFor each test case, output the answer mod 1000000007Sample Input1 11 12 11 2Sample Output126Authorhanshuai
这道题的题意怎么说呢,就是有一个密码锁,有n个转动的轮子,这些轮子都最多可以从'a'撞到'z',现在给你一些特定的区间序列[l,r],意思是这个区间的转轮要一起同时转动。如果转动出现的结果与其他方法转动出现的结果一样,那么他们就视为一把同密码所。例如:给你区间[1,5],你可以同时转动区间1~5,出现的结果与你想转1,再转2...再转动5之后的结果是一样的,那么他们就视为同一把锁。那么怎么做这道题呢,拿就要用到并差集了。首先,我们把每个转轮看成一个区间,那么密码锁就有26^n种。接着,就要用到并查集了。首先呢,1~5是一个集合,那么我们这个区间的密码锁数其实就是26^(5-1),这个应该都清楚吧。我们现在就是要统计有多少个转动的区间。怎么用并查集呢。首先,给你区间[2,4],[4,5]和[2,3],[4,5],虽然他们有转动的都在[2,5],可是对于[2,4]和[4,5]这两个区间,4这个位置一次转动两次,而[2,5]只转动了一次而已,所以这是三个可转动的区间。如果给你[2,3],[4,5]和[2,5],[2,3]和[4,5]转动的结果其实和[2,5]是一样的,所以[2,3]+[4,5]等同于[2,5],这里其实就只有二个可转动的区间。像[2,3],[4,5],[2,5]这样的可以用到并差集把大区间[2,5]去掉。具体为什么用merge(l,r+1),其实就是很好懂,[2,4],[4,6],[2,6],那么(2,4,6)不就在同个集合里面了吗,其他区间也这样处理,不会受到影响。merge(l-1,r)也是可以的。最后结果就是(26^(N-Mx))%MOD,这里(N-Mx)太大,我们可以用快速幂来解决。
#include<iostream>#include<cstring>#include<cstdlib>#include<algorithm>#include<cctype>#include<cmath>#include<ctime>#include<string>#include<stack>#include<deque>#include<queue>#include<list>#include<set>#include<map>#include<cstdio>#include<limits.h>#define MOD 1000000007#define fir first#define sec second#define fin freopen("/home/ostreambaba/文档/input.txt", "r", stdin)#define fout freopen("/home/ostreambaba/文档/output.txt", "w", stdout)#define mes(x, m) memset(x, m, sizeof(x))#define Pii pair<int, int>#define Pll pair<ll, ll>#define INF 1e9+7#define inf 0x3f3f3f3f#define Pi 4.0*atan(1.0)#define lowbit(x) (x&(-x))#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define max(a,b) a>b?a:btypedef long long ll;typedef unsigned long long ull;const double eps = 1e-9;const int maxn = 10000000+5;const int maxm = 10000005;using namespace std;inline int read(){    int x(0),f(1);    char ch=getchar();    while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();    return x*f;}int p[maxn];int ans;inline int find(int x){    return x==p[x]?x:p[x]=find(p[x]);}void merge(int x,int y){    x=find(x);    y=find(y);    if(x!=y){        p[y]=x;        --ans;    }}inline ll pow(int x){    ll res=1;    if(0==x){        return res;    }    ll n=26;    while(x){        if(x&1){            res=(res*n)%MOD;        }        n=(n*n)%MOD;        x>>=1;    }    return res;}int main(){    int n,m;    while(~scanf("%d%d",&n,&m)){        ans=n;        for(int i=1;i<=n+1;++i){            p[i]=i;        }        int l,r;        while(m--){            cin>>l>>r;            merge(l,r+1);        }        printf("%lld\n",pow(ans));    }    return 0;}
0 0
原创粉丝点击