题意描述:有一个类似滚轮式的密码锁放在一排共n个,有m种操作每次操作一个区间,且此次操作后的所有密码相同,问最多能形成多少种密码
解决:将区间分为可变部分和不可变部分,没当有可变部分时候总区间数要减去一。因为在可变 区间内第一个滚轮一定是固定的(可以转)
并查集合并区间后做下快速幂就好了 1 //组合数学+快速幂+并查集
2 //统一区间内的组合数指数在原先基础上要减去1
3 //证明可以枚举开始的字母因为是循环的所以第一个字母唯一
4 //注意边界重叠的情况,初始化要从0开始
5
6 #include<cstring>
7 #include<cstdio>
8 #include<algorithm>
9 typedef long long ll;
10 using namespace std;
11 const int MAX = 10000000+10;
12 const int MOD = 1000000007;
13 int pa[MAX];
14 void make(int n)
15 {
16 for(int i=0;i<=n;i++) pa[i]=i;
17 }
18 int find(int x)
19 {
20 return pa[x]==x? x: pa[x]=find(pa[x]);
21 }
22 int Union(int a,int b)
23 {
24 int fx=find(a);
25 int fy=find(b);
26 if(fx==fy) return 0;
27 else
28 {
29 pa[fx]=fy;
30 return 1;
31 }
32 }
33 ll qmod(ll a,ll n)
34 {
35 ll res=1;
36 while(n>0)
37 {
38 if(n&1) res=res*a%MOD;
39 a=a*a%MOD;
40 n>>=1;
41 }
42 return res;
43 }
44 int main()
45 {
46 int n,m,l,r;
47 while(scanf("%d %d",&n,&m)>0)
48 {
49 make(n); int cnt=0;
50 for(int i=0;i<m;i++)
51 {
52 scanf("%d %d",&l,&r);
53 if(Union(l-1,r)) cnt++;
54 }
55 ll ans=qmod(26,(ll)(n-cnt));
56 printf("%I64d ",ans%MOD);
57 }
58 return 0;
59 }
3 //证明可以枚举开始的字母因为是循环的所以第一个字母唯一
4 //注意边界重叠的情况,初始化要从0开始
5
6 #include<cstring>
7 #include<cstdio>
8 #include<algorithm>
9 typedef long long ll;
10 using namespace std;
11 const int MAX = 10000000+10;
12 const int MOD = 1000000007;
13 int pa[MAX];
14 void make(int n)
15 {
16 for(int i=0;i<=n;i++) pa[i]=i;
17 }
18 int find(int x)
19 {
20 return pa[x]==x? x: pa[x]=find(pa[x]);
21 }
22 int Union(int a,int b)
23 {
24 int fx=find(a);
25 int fy=find(b);
26 if(fx==fy) return 0;
27 else
28 {
29 pa[fx]=fy;
30 return 1;
31 }
32 }
33 ll qmod(ll a,ll n)
34 {
35 ll res=1;
36 while(n>0)
37 {
38 if(n&1) res=res*a%MOD;
39 a=a*a%MOD;
40 n>>=1;
41 }
42 return res;
43 }
44 int main()
45 {
46 int n,m,l,r;
47 while(scanf("%d %d",&n,&m)>0)
48 {
49 make(n); int cnt=0;
50 for(int i=0;i<m;i++)
51 {
52 scanf("%d %d",&l,&r);
53 if(Union(l-1,r)) cnt++;
54 }
55 ll ans=qmod(26,(ll)(n-cnt));
56 printf("%I64d ",ans%MOD);
57 }
58 return 0;
59 }