1. 程式人生 > >Pseudoforest 【HDU - 3367】【並查集+(可以忽略的離散化)】

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;
}