zoukankan      html  css  js  c++  java
  • 带权并查集:CF-2015 ACM Arabella Collegiate Programming Contest(F题)

    F. Palindrome

    Problem Description

    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 (10^9 + 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


    解题心得:

    1. 这个题的题意就是给你一个字符串,里面包含小写字母和?,字符串必须是回文串并且给你m对数,该数位置对应的字母应该相等。?可以替换成任意的26个小写字母,问一共有多少种形成规定回文串的可能。
    2. 在做这个题的时候是比赛,比赛很简单,这个题是最后一个,没想到是一个简单的带权并查集,当时在用搜索硬怼,写了一大堆代码,很恼火,还是不够冷静啊。
    3. 就这个题来说如果细分很麻烦,又是回文又是位置对应还有?替换。其实思维到位了就完全不用那么麻烦,直接将该合并的合并,回文位置合并,对应位置合并,合并之后在从根节点开始找,看同一个根的集合里面的元素,如果不对应,不回文的直接输出0就行了,只有该集合全部是?的才可以用answer乘以26(因为一个集合里面的?必须相等)。每一个集合里面的字母必须全部相等,或者全是?。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 5e4+100;
    const int MOD = 1e9+7;
    char s[maxn];
    int father[maxn];
    vector <int> ve[maxn];
    
    int find(int x)
    {
        if(father[x] == x)
            return x;
        else
            return father[x] = find(father[x]);
    }
    
    int main()
    {
        int len,m;
        int t;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&len,&m);
            for(int i=0; i<=len; i++)
            {
                father[i] = i;
                ve[i].clear();
            }
            scanf("%s",s);
    
            //对应位置的不用管直接合并
            while(m--)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                a--,b--;
                int fa = find(a);
                int fb = find(b);
                if(fa != fb)
                    father[fa] = fb;
            }
            int Len = len / 2;
    
            //回文位置的不用管也直接合并
            for(int i=0; i<len; i++)
            {
                int fa = find(i);
                int fb = find(len-1-i);
                if(fa!=fb)
                    father[fa] = fb;
            }
    
            bool flag = false;//用来记录是否是符合规定的回文串
    
            //同一根节点的集合全部记录下来
            for(int i=0; i<len; i++)
            {
                int f = find(i);
                ve[f].push_back(i);
            }
    
            long long ans = 1;
            for(int i=0; i<len; i++)
            {
                char c = 'A',cnt = 0;
                Len = ve[i].size();
                if(!Len)
                    continue;
                for(int j=0; j<Len; j++)
                {
                    if(s[ve[i][j]] == '?')//该集合里面的?的数目记录一下
                        cnt++;
                    else if(s[ve[i][j]] != c && c == 'A')//记录该集合里面的字幕
                        c = s[ve[i][j]];
                    else if(s[ve[i][j]] != c && c != 'A')//一个集合里面出现了两种不同的字母,不符合要求
                        flag = true;
                }
    
                if(Len == cnt)//一个集合里面全是?(所有?必须替代成同一个字母)
                {
                    ans = (ans * 26)%MOD;
                }
            }
            if(flag)
            {
                printf("0
    ");
                continue;
            }
            printf("%d
    ",ans);
        }
    }
    
  • 相关阅读:
    asp.net core 集成JWT(一)
    Microsoft.Extensions.DependencyInjection中的Transient依赖注入关系,使用不当会造成内存泄漏
    Microsoft.Extensions.DependencyInjection的Singleton依赖注入关系,只是对于同一个ServiceProvider是单例的
    ASP.NET Core MVC中,如何将视图文件生成的html代码通过字符串返回
    SpringBoot魔法堂:说说带智能提示的spring-boot-starter
    Maven魔法堂:安装Oracle JDBC Driver依赖的那些坑
    TypeScript魔法堂:函数类型声明其实很复杂
    TypeScript魔法堂:枚举的超实用手册
    C#获取文件与文件夹默认图标(2006-3-22 新增示例代码与程序)
    【学习笔记】Team Explorer for Microsoft Visual Studio2015 安装时发生严重错误
  • 原文地址:https://www.cnblogs.com/GoldenFingers/p/9107314.html
Copyright © 2011-2022 走看看