Pseudoforest 【HDU - 3367】【并查集+(可以忽略的离散化)】

题目链接


  翻译的有点不准确,还是靠自我的理解吧,呐,具体是这样的:第一行 N, M,  接下来有M行,N代表有几个字母组成, M代表有多少个可操作区间。

  然后讲一下几个测试样例:

样例一:

表示只有一个字母,这个字母可以是a.....z, 1代表下面只有一个操作区间,就是1 1, 
当这个字母是a时, 它经过1 1这个操作区间进行有限次的“增加”后,可以变成b,c,d....z,那么a和b,....z就是同一种锁,
当这个字母是b时, 它经过1 1这个操作区间进行有限次的“增加”后,可以变成a,  c,d....z,因为a,....z已经是同一种锁了,,如果这个字母是c....,后面就是一样的,永远是这26个字母,说明是唯一的解:ans==1

样例二:

2 1
1 2

意思是有两个字母,以及一次操作,为1~2:当这两个字母是ab,在可操作区间1 2,它可以变成bc,cd,.....za;那么ab和bc,cd,.....za就是同种锁;当这两个字母是bc时, 当这两个字母是cd时......等等,这都和当字母是ab时相同,这算一种锁;当字母是ac时,字母ac 和 bd.......zb都是属于同种锁;发现,后面的可能只会随着首字与第二字符的大小来产生个数,第二字符与第一字符的差距可以为0~25,%26只有这26种可能。ans==26


  那么这该如何解呢?尤其是第一个样例还有1~1这样的区间,我们该如何求解?譬如待查询区间为L~R,那么,我们把他们化为L~R+1也没多少区别?为什么这么说呢?我们该如何求解这到底有多少种方案数,如果有一组相互对应,那么26的N次方就会少一组,这个可以自推。然后,为了避免重复,我们将原区间看作L~R+1来处理。

  我在这题中还用了离散化的思想(题看错了,数据看大了),不过可以看下,就当练习自己离散化能力了。


#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
using namespace std;
typedef unsigned long long ull;
const int mod=1e9+7;
const int maxN=1005;
typedef long long ll;
int N, M, m, a[maxN<<1], root[maxN<<1], diff, num[maxN<<1], cnt;
bool cmp(int e1, int e2) { return e1<e2; }
map<int, int> mp;
void init()
{
    cnt=0;
    mp.clear();
    for(int i=1; i<=m; i++) { root[i]=i; }
}
ll fast_mi(ll x, int y)
{
    ll ans=1;
    while(y)
    {
        if(y&1) ans = (ans*x)%mod;
        x = (x * x)%mod;
        y>>=1;
    }
    return ans;
}
struct Eddge
{
    int no, to;
    Eddge(int a=0, int b=0):no(a), to(b) {}
}edge[maxN];
int fid(int x) { return x==root[x]?x:(root[x]=fid(root[x])); }
void mix(int x, int y)
{
    int u=fid(x), v=fid(y);
    if(u != v)
    {
        root[u] = v;
        cnt++;
    }
}
int main()
{
    while(scanf("%d%d", &N, &M)!=EOF)
    {
        m = 2*M;
        for(int i=1; i<=M; i++)
        {
            scanf("%d%d", &edge[i].no, &edge[i].to);
            a[2*i-1] = edge[i].no;
            a[2*i] = edge[i].to + 1;
        }
        init();
        sort(a+1, a+1+m, cmp);
        diff = (int)(unique(a+1, a+1+m) - a - 1);
        //printf("diff: %d\n", diff);
        for(int i=1; i<=diff; i++)
        {
            mp[a[i]]=i;
            //printf("%d\n", a[i]);
        }
        for(int i=1; i<=M; i++)
        {
            mix(mp[edge[i].no], mp[edge[i].to+1]);
        }
        printf("%lld\n", fast_mi(26, N-cnt)%mod);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值