并查集

本文介绍了一个算法问题:如何计算在给定约束条件下,通过替换问号使得字符串成为回文串的不同方式的数量。采用并查集解决字符匹配问题,并提供了一个C++实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Palindrome

A string is palindrome if it can be read the same way in either direction, for example “maram” is
palindrome, while “ammar” is not.
You are given a string of n characters, where each character is either a lowercase English letter or
a question mark (?). You are also given a set of m constraints. Your task is to count the number of
ways in which we can replace all question marks with lowercase English letters such that the
resulting string is a palindrome that does not violate the given constraints.
The constraints are in the form of pairs of indices of letters that should be the same.

Input

The first line of input contains one integer T, the number of test cases (1 ≤ T ≤ 256).
Each test case begins with two integers: n representing the string size (1 ≤ n ≤ 50000) and m
representing the number of constraints (0 ≤ m ≤ 10000).
The next line contains a string of length n. The next m lines, each contains two integers x and y (1
<= x < y <= n), where letters at index x and index y must be the same.
Test cases are separated by a blank line.

Output

For each test case, print the number of ways modulo 1,000,000,007 (109
+ 7).

Sample Input
4
5 1
ma??m
1 5
5 4
ma??m
1 2
1 5
1 3
3 4
7 0
acm?cpc
4 1
????
1 4
Sample Output
26
0
0
676

这题用并查集过了,没想到啊

#include<cstdio>
#include<vector>
using namespace std;
const int N = 1e5 + 50;
const long long mod = 1e9 + 7;
char s[N];
vector<int>e[N];
int n, m,fa[N];
int find_fa(int x)
{
    if (x == fa[x]) return x;
    fa[x] = find_fa(fa[x]);
    return find_fa(fa[x]);
}
int main()
{
    int t;
    scanf("%d",&t);
    while (t--) {
        scanf("%d%d",&n,&m);
        scanf("%s",s+1);
        for (int i = 0; i <= n; i++) e[i].clear();
        for (int i = 1; i <= m; i++) {
            int a, b;
            scanf("%d%d",&a,&b);
            e[a].push_back(b);
        }
        for (int i = 1; i <= n; i++) {
            e[i].push_back(n - i + 1);
        }
        for (int i = 0; i <= n; i++) fa[i] = i;
        bool flag = 1;
        for (int i = 1; i <= n; i++) {
            for (int j = 0; j < e[i].size(); j++) {
                int v = e[i][j];
                int f1 = find_fa(i);
                int f2 = find_fa(v);
                if (f1 != f2) {
                    if (s[f1] != '?'&&s[f2] != '?'&&s[f1] != s[f2]) {
                        flag = 0; break;
                    }
                    else if (s[f1] != '?'&&s[f2] == '?') s[f2] = s[f1];
                    fa[f1] = f2;
                }
            }
        }
        int cnt = 0;
        for (int i = 1; i <= n; i++) {
            if (fa[i] == i&&s[i] == '?') cnt++;
        }
        if (flag == 0) printf("0\n");
        else {
            long long ans = 1;
            for (int i = 1 ;i <= cnt; i++)
                ans = ans * 26 % mod;
            printf("%I64d\n",ans);
        }
    }
    return 0;
}

以后再更

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值