题意:给出一个由 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) (N≤107,M≤103)
锁啊,感觉是置换
慢慢推广
如果
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=26N−1
如果只有一个可操作区间 [ p , p + k − 1 ] [p,p+k-1] [p,p+k−1],同样有 A n s = 2 6 N − 1 Ans=26^{N-1} Ans=26N−1
很显然 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,p−1]+Ans[p,p+k−1]+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 pi−p1
显然 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+k−1]相当于 2 6 k − 1 26^{k-1} 26k−1,那么 A n s t o t a l = 2 6 N − 1 Ans_{total}=26^{N-1} Anstotal=26N−1
如果只有 k k k个不相交的可操作区间,那么 A n s = 2 6 N − k Ans=26^{N-k} Ans=26N−k
考虑多个区间,有相交部分。
- 如果存在区间 [ p 1 , p 2 ] , [ p 2 , p 3 ] , ⋯   , [ p n − 1 , p n ] [p_1,p_2],[p_2,p_3],\cdots,[p_{n-1},p_n] [p1,p2],[p2,p3],⋯,[pn−1,pn]和 [ p 1 , p n ] ( p a < p b ( a < b ) ) [p_1,p_n](p_a<p_b(a<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 , ⋯   , 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 pn→pn−1,pn−1→pn−2,⋯,p3→p2,p2→p1
这个时候遇见了区间 [ 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=26N−cnt
#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;
}