[HDU3461] [2010多校联考3] Code Lock [并查集]

题意:给出一个由 N N N个字母组成的锁。
给出 M M M个区间 [ L , R ] [L,R] [L,R],每次操作可以将某个区间中所有字母变为字典序中的下一个字母。
特殊地,‘z’会变成’a’。
如果一把锁通过对可操作区间的有限次操作可以得到另一个锁,那么认为这两个锁是相同的。
请求出一共有多少种不同的锁 % 1 e 9 + 7 \%1e9+7 %1e9+7
( N ≤ 1 0 7 , M ≤ 1 0 3 ) (N\le10^7,M\le10^3) (N107,M103)

锁啊,感觉是置换

慢慢推广
如果 M = 0 M=0 M=0 A n s = 2 6 N Ans=26^N Ans=26N

如果只有一个可操作区间,长度为 1 1 1,很显然 A n s = 2 6 N − 1 Ans=26^{N-1} Ans=26N1

如果只有一个可操作区间 [ p , p + k − 1 ] [p,p+k-1] [p,p+k1],同样有 A n s = 2 6 N − 1 Ans=26^{N-1} Ans=26N1

很显然 A n s t o t a l = A n s [ 1 , p − 1 ] + A n s [ p , p + k − 1 ] + A n s p + k , N Ans_{total}=Ans_{[1,p-1]}+Ans_{[p,p+k-1]}+Ans_{p+k,N} Anstotal=Ans[1,p1]+Ans[p,p+k1]+Ansp+k,N
那么这个区间可以当作 [ 1 , k ] [1,k] [1,k]来想,里面有 p 1 , p 2 , ⋯   , p k p_1,p_2,\cdots,p_k p1,p2,,pk k k k个数。
由于把 [ 1 , k ] [1,k] [1,k]全部 + 1 +1 +1并不改变区间内每个数的相对大小,我们记 p i p_i pi的相对大小为 p i − p 1 p_i-p_1 pip1
显然 p 1 p_1 p1的相对大小永远为 0 0 0,所以 p 1 p_1 p1对答案没有任何贡献
A n s [ p , p + k − 1 ] Ans_{[p,p+k-1]} Ans[p,p+k1]相当于 2 6 k − 1 26^{k-1} 26k1,那么 A n s t o t a l = 2 6 N − 1 Ans_{total}=26^{N-1} Anstotal=26N1

如果只有 k k k个不相交的可操作区间,那么 A n s = 2 6 N − k Ans=26^{N-k} Ans=26Nk

考虑多个区间,有相交部分。

  • 如果存在区间 [ p 1 , p 2 ] , [ p 2 , p 3 ] , ⋯ &ThinSpace; , [ p n − 1 , p n ] [p_1,p_2],[p_2,p_3],\cdots,[p_{n-1},p_n] [p1,p2],[p2,p3],,[pn1,pn] [ p 1 , p n ] ( p a &lt; p b ( a &lt; b ) ) [p_1,p_n](p_a&lt;p_b(a&lt;b)) [p1,pn](pa<pb(a<b))
    那么区间 [ p 1 , p n ] [p_1,p_n] [p1,pn]存不存在都差不多,显然可以去掉它。问题就是怎么判断这种情况
    我们可以考虑连接 p n → p n − 1 , p n − 1 → p n − 2 , ⋯ &ThinSpace; , p 3 → p 2 , p 2 → p 1 p_n\to p_{n-1},p_{n-1}\to p_{n-2},\cdots,p_3\to p_2,p_2\to p_1 pnpn1,pn1pn2,,p3p2,p2p1
    这个时候遇见了区间 [ p 1 , p n ] [p_1,p_n] [p1,pn],却发现 p n p_n pn已经连在 p 1 p_1 p1上了,就可以无视这个区间。
  • 而不是上面那种情况的话,显然可以看作这些区间是不相交的。
    于是有几个区间就当作有几个不相交区间算。

所以我们只需要记录有效区间数 c n t cnt cnt A n s = 2 6 N − c n t Ans=26^{N-cnt} Ans=26Ncnt

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<cctype>
using namespace std;
#define LL long long
const LL MOD=1000000007;
int N,M,x,y,fx,fy,ans=0;
int fa[10000005]={};
LL quick_pow(int T)
{
	LL Ans=1ll,Base=26ll;
	while(T)
	{
		if(T&1)Ans=(Ans*Base)%MOD;
		Base=(Base*Base)%MOD;
		T>>=1;
	}
	return Ans;
}
int find(int x){return (fa[x]==x)?x:(fa[x]=find(fa[x]));}
int main()
{
	while(~scanf("%d%d",&N,&M))
	{
		for(int i=0;i<=N;++i)fa[i]=i; ans=0;
		while(M--)
		{
			scanf("%d%d",&x,&y); --x;
			fx=find(x),fy=find(y);
			if(fx!=fy)fa[fy]=fx,++ans;
		}
		printf("%lld\n",quick_pow(N-ans));
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值