题意:给出一个字符串,其中有?的代表未填的字符,在?中可以填入任意小写英文字母,问有多少种填法可以使得字符串为回文字符串并且满足所给的m个要求:给出的两个位置的字符要相同。
题解:用并查集。先对字符串中位置对称的字符进行处理,再对每个要求中的两个字符进行处理。处理方式:
1.如果两个字符相同,则将他们则以任意一个点为根节点。
2.如果其中一个字符是'?',则一另一个字符为根节点。
3.如果不相同且都不为'?',则不存在回文串,输出0。
根节点确定的点只有1种固定填法,根节点为’?‘的有26种填法。
然后找出所有根节点为'?'的字符的个数n个,每一个?都可以填入任意的26个字母,有26^n中。记得取模。
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
using namespace std;
const int mod = 1e9 + 7;
int t,n,m,flag,fa[50010];
char s[50010];
int Find(int x)
{
if(x == fa[x]) return x;
return fa[x] = Find(fa[x]);
}
void unite(int x,int y)
{
if(s[x] == s[y]) fa[x] = y;
else if(s[x] == '?') fa[x] = y;
else if(s[y] == '?') fa[y] = x;
else flag = 0;
}
int init()
{
int cnt = 0;
for(int i = 1;i <= n;i++) fa[i] = i;
for(int i = 1;i <= (n + 1) / 2;i++) unite(i,n + 1 - i);
for(int i = 1;i <= m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
x = Find(x),y = Find(y);
unite(x,y);
}
for(int i = 1;i <= n;i++)
{
if(s[i] == '?' && fa[i] == i)
cnt++;
}
return cnt;
}
int main()
{
scanf("%d",&t);
while(t--)
{
flag = 1;
scanf("%d%d%s",&n,&m,s + 1);
int cont = init();
long long ans = 1;
if(!flag)
{
printf("0\n");
continue;
}
for(int i = 1;i <= cont;i++)
ans = ans * 26 % mod;
printf("%I64d\n",ans);
}
return 0;
}