HDU 3461 Code Lock(并查集,合并区间,思路太难想了啊)

完全没思路,题目也没看懂,直接参考大牛们的解法。

http://www.myexception.cn/program/723825.html

题意是说有N个字母组成的密码锁,如[wersdfj],每一位上的字母可以转动,变成字母表中的下一位。 如w可转动变成x,z变成a。但是题目规定,只能同时转动某个区间上的所有字母,如[1,3], 那么第1到第3个的所有字母要同时转动, 那么[wersdfj]经过一次操作就变成[xfssdfj].一共有M个区间是可以操作的。 

经过可操作区间进行的操作得到的所有情况,都是同一个的。 也就是指不管我在题目给出的某一个区间怎么转动,其它位上的字母都不变,它仍视为同一种。

假如原本是[abc],给出可操作区间[1,2],即我可以转动第一个、第二个字母,当然是同时转动的。 由于[1,2]区间情况所能变化得到的,都视为同一种。我不妨固定第一个字母,就为a,其余25个字母可有a变化得到。 那么第二位上的字母,就可以有26种可能,也就是[1,2]区间可能的情况有26种,再加上独立的第3个字母有26种可能,总共有26^2种。

也就是说,有n个字母组成的密码锁,原本会有26^n种。如果有一个可操作区间,那么会有26次变换。 相当于这个操作区间就减少了原来的26种,总的也就变为26^(n-1)。 也就是现在我们要统计有多少个可操作区间,若为cnt,则答案即为26^(n-cnt),这当然要用到快速幂。

至于怎么求区间个数,采用的是区间合并的方法,给出一个区间[L,R],若可以合并,则cnt++。

不过这里有一个情况要注意:

假设有区间[1,3],[3,5],[1,5],如果按照Union(L, R)来算, 那么[1,3],[3,5]可以合并,cnt为2, 但[1,5]因为已经属于同一个集合,则不合并。那么得到两种可操作区间。 但实际上是有3中可操作区间的,因为1~3, 3~5是有重叠了3的两个区间,所以1~5区间的情况不包括在前两个区间的情况内。

如果是[1,3],[4,5],[1,5],如果合并的话,cnt为3,但实际就只有两种情况,因为最后一种的转动情况包含在了前两种转动的情况之内了。

这里大牛们就想出了一个解决办法:

合并[L-1,R]或者[L,R+1]。

如上述区间[1,3],[3,5],[1,5],[1,3]合并的是[0,3],[3,5]合并的是[2,5],[1,5]合并的是[0,5],这样cnt=3;

如果是[1,3],[4,5],[1,5],那么cnt=2;

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>

using namespace std;

const int maxn=10000005;
const int mod=1000000000+7;
int father[maxn];
int n,m;

void init(){
    for(int i=0;i<=n;i++)
        father[i]=i;
}

int find_root(int x){
    if(father[x]!=x)
        father[x]=find_root(father[x]);
    return father[x];
}

bool Union(int a,int b){
    int x=find_root(a);
    int y=find_root(b);
    if(x==y)
        return false;
    father[y]=x;
    return true;
}

//注意要long long ,即使a(26)也要定义成long long
long long quickPow(long long a,int b){
    long long ans=1;
    while(b>0){
        if(b&1){
            ans=(ans*a)%mod;
        }
        a=a*a%mod;
        b=b>>1;
    }
    return ans;
}

int main()
{
    int l,r;
    while(scanf("%d%d",&n,&m)!=EOF){
        int cnt=0;
        init();
        for(int i=1;i<=m;i++){
            scanf("%d%d",&l,&r);
            l--;
            if(Union(l,r))
                cnt++;
        }
        long long ans=quickPow(26,n-cnt);
        printf("%I64d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/chenxiwenruo/p/3296423.html