思路: 并查集+离散化+快速幂
分析:
1 题目给定长度为n的字符串,然后给定m个操作,询问最后的不同字符串的个数
2 考虑长度为n的时候,因为每个字符有26种情况('a'~'z'),所以有26^n。因为有m次的操作,题目中说了如果可以被变换那么认为是相同的字符串,那么不同的字符串就是所有不被操作区间的组合
3 那么我们利用并查集去求有操作的集合的个数,比如[1,3],[3,5]和[1,5]是三个集合,而[1,3],[4,5]和[1,5]则是2个集合
4 对于区间[l,r],那么我们一般转化为处理(l-1,r],这样不用考虑端点的问题了,最后利用快速幂求出ans即可
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int MOD = 1e9+7; const int MAXN = 2001; struct Node{ int x; int y; }; Node node[MAXN]; int n , m , pos; int num[MAXN]; int father[MAXN]; void init(){ sort(num , num+pos); pos = unique(num , num+pos)-num; for(int i = 0 ; i <= pos ; i++) father[i] = i; } int search(int x){ int left = 0; int right = pos-1; while(left <= right){ int mid = (left+right)>>1; if(num[mid] == x) return mid+1; else if(num[mid] < x) left = mid+1; else right = mid-1; } } int find(int x){ if(father[x] != x) father[x] = find(father[x]); return father[x]; } long long quickPow(long long m , long long n){ long long sum = 1; while(n){ if(n&1) sum = (sum*m)%MOD; n >>= 1; m = (m*m)%MOD; } return sum%MOD; } void solve(){ int cnt = n; for(int i = 0 ; i < m ; i++){ int x = search(node[i].x); int y = search(node[i].y); int fx = find(x); int fy = find(y); if(fx != fy){ father[fx] = fy; cnt--; } } printf("%lld\n" , quickPow(26 , cnt)); } int main(){ int x , y; while(scanf("%d%d" , &n , &m) != EOF){ pos = 0; for(int i = 0 ; i < m ; i++){ scanf("%d%d" , &node[i].x , &node[i].y); node[i].x--; num[pos++] = node[i].x; num[pos++] = node[i].y; } init(); solve(); } return 0; }