题意:给出一个由
N个字母组成的锁。
给出
M个区间
[L,R],每次操作可以将某个区间中所有字母变为字典序中的下一个字母。
特殊地,‘z’会变成’a’。
如果一把锁通过对可操作区间的有限次操作可以得到另一个锁,那么认为这两个锁是相同的。
请求出一共有多少种不同的锁
%1e9+7。
(N≤107,M≤103)
锁啊,感觉是置换
慢慢推广
如果
M=0有
Ans=26N
如果只有一个可操作区间,长度为
1,很显然
Ans=26N−1
如果只有一个可操作区间
[p,p+k−1],同样有
Ans=26N−1
很显然
Anstotal=Ans[1,p−1]+Ans[p,p+k−1]+Ansp+k,N
那么这个区间可以当作
[1,k]来想,里面有
p1,p2,⋯,pk共
k个数。
由于把
[1,k]全部
+1并不改变区间内每个数的相对大小,我们记
pi的相对大小为
pi−p1
显然
p1的相对大小永远为
0,所以
p1对答案没有任何贡献
Ans[p,p+k−1]相当于
26k−1,那么
Anstotal=26N−1
如果只有
k个不相交的可操作区间,那么
Ans=26N−k
考虑多个区间,有相交部分。
- 如果存在区间
[p1,p2],[p2,p3],⋯,[pn−1,pn]和
[p1,pn](pa<pb(a<b))
那么区间
[p1,pn]存不存在都差不多,显然可以去掉它。问题就是怎么判断这种情况
我们可以考虑连接
pn→pn−1,pn−1→pn−2,⋯,p3→p2,p2→p1
这个时候遇见了区间
[p1,pn],却发现
pn已经连在
p1上了,就可以无视这个区间。
- 而不是上面那种情况的话,显然可以看作这些区间是不相交的。
于是有几个区间就当作有几个不相交区间算。
所以我们只需要记录有效区间数
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;
}