[BestCoder Round #3] hdu 4909 String (状压,计数)

String

Problem Description

You hava a non-empty string which consists of lowercase English letters and may contain at most one ‘?‘. Let‘s choose non-empty substring G from S (it can be G = S). A substring of a string is a continuous subsequence of the string. if G contains ‘?‘ then ‘?‘
can be deleted or replaced by one of lowercase english letters. After that if each letter occurs even number of times in G then G is a good substring. Find number of all good substrings.

Input

The input consists of an integer T, followed by T lines, each containing a non-empty string. The length of the string doesn‘t exceed 20000.

[Technical Specification]

1 <= T <= 100

Output

For each test case, print a single integer which is the number of good substrings of a given string.

Sample Input

3
abc?ca
aabbcc
aaaaa

Sample Output

7
6
6

Hint

Good substrings of "abc?ca": "?", "c?", "?c", "c?c", "bc?c", "c?ca", "abc?ca"

Source

BestCoder Round #3

解题思路:

题意为给定一个包含小写字母的序列,其中可能有一个‘?‘,也可能没有,有的话最多只有一个,‘?‘可以删除,也可以替换为任意一个小写字母,问给定的序列中有多少个连续的子序列,保证所有小写字母出现的次数为偶数。

用一个26位二进制数来表示状态,每一位代表一个小写字母,关键是:

当一个状态出现时,后面又加上几个连续的字母,(状态的改变用状态的某一位异或1,)该状态又一次出现了,那么加上的那几个连续字母是符合题意的一个串,只有异或偶数倍某一位的状态才能回到本身, 比如一开始某一位的状态为0,异或一次0^1=1,  1^1=0......  再比如是1,  1^1=0,0^1=1

要求记录每个状态出现的次数,那么26位,状态有 2^26-1个,用map<int,int>hash来模拟数组

hash[x] ,代表状态x出现的次数

对于有出现’?‘的串,可以分为三部分,?之前部分符合题意的串,之后部分符合题意的串,加上?以后符合题意的串,具体思路在代码注释中。

参考:http://blog.csdn.net/accelerator_/article/details/38363245#comments  由于作者文章没有注释,代码看了好半天,才慢慢弄懂。。。。

代码:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <map>
using namespace std;
const int maxn=20010;
char str[maxn];
int cas,n,p,x;
int ans;
map<int,int>hash;//hash[x]表示状态x出现了多少次

int main()
{
    scanf("%d",&cas);
    while(cas--)
    {
        hash.clear();
        scanf("%s",str);
        p=-1;
        n=strlen(str);
        for(int i=0;i<n;i++)
        {
            if(str[i]=='?')
            {
                p=i;
                break;
            }
        }
        ans=0;

        if(p==-1)//一个状态出现过,后面又加了几个字母,而这个状态又重新出现了,说明后面加的
        {        //每个字母都是偶数个,因为0^1=1,1^1=0
            x=0;
            hash[0]++;
            for(int i=0;i<n;i++)
            {
                x^=(1<<(str[i]-'a'));
                ans+=hash[x];//前面出现过hash[x]次,加上它
                hash[x]++;
            }
            printf("%d\n",ans);
            continue;
        }
        else
        {
            x=0;//计算'?'前面的串符合题意的有多少个
            hash[0]++;
            for(int i=0;i<p;i++)
            {
                x^=(1<<(str[i]-'a'));
                ans+=hash[x];
                hash[x]++;
            }
            hash.clear();//注意此时清空,后面的串是独立计算的

            x=0;//计算'?'后面的串符合题意的有多少个
            hash[0]++;
            for(int i=p+1;i<n;i++)
            {
                x^=(1<<(str[i]-'a'));
                ans+=hash[x];
                hash[x]++;
            }

            x=0;
            if(hash.count(x))
                ans+=hash[x];
            //花了N长时间终于明白上面这句话什么意思了
            //把?看做空串(也可以理解为删除)和后面的串一块,有多少符合题意的,这时候状态是0

            for(int i=0;i<26;i++)//枚举?的值与后面的串一块,有多少符合题意的
            {
                if(hash.count(x^(1<<i)))
                    ans+=hash[x^(1<<i)];
            }

            for(int i=p-1;i>=0;i--)//处理前部分时,和?以及后半部分建立了联系,注意一定是逆向,不能是正向,
            {
                x^=(1<<(str[i]-'a'));
                if(hash.count(x))//寻找后半部分出现相同的状态,此时?为空, 这也是要逆向的原因
                    ans+=hash[x];

                for(int j=0;j<26;j++)//枚举?的值
                {
                    if(hash.count(x^(1<<j)))
                        ans+=hash[x^(1<<j)];
                }
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}

简要介绍下hash.count(x)这个函数,转载于网络

count()是返回key出现的次数,在map里,key只能是0和1

例如 我们判断一个key是否存在,如果存在就输出,不存在就不输出

map<string, int> a;

cout<<a["abc"]<<endl; //这个肯定是错的

if(a.count("China"))        //对了

cout<<a["China"]<<endl;

map<string,int>::iterator fi=a.find("China");//查找是否有"China",返回一个迭代器

if(fi!=a.end()) cout<<a->second;//找到了,输出"China"对应的int值

[BestCoder Round #3] hdu 4909 String (状压,计数)

时间: 2024-12-23 19:53:11

[BestCoder Round #3] hdu 4909 String (状压,计数)的相关文章

hdu 4909 String (map + 状压)

题目大意: 给定一个可能含'?'的字符串.然后问这个字符串有多少个子串是含有所有的字符都只出现两次. 其中'?' 可以被替换成任意字符,也可以被remove... 思路分析: 这是bestcoder的round #3的第三题. 这道题的做法和 4908 的做法差不多. 我们把 '?' 左右两边的状态分别处理出来. 然后用map 计数.然后枚举左边的状态.同时枚举? 对应的字符. 然后去寻找右边对应的状态,此时 ans 就可以加上答案. 注意的是要考虑到以 ? 结尾的情况.所以在 ? 的状态要和上

HDU 4909 String 统计+状压

因为连续异或满足区间减法性质,所以可以状压之后用异或来判断是否为符合条件的单词并且存储次数 一开始用map,一直超时.虽然直接用开1<<26的数组内存存的下,但是memset的时间肯定会超,但是只要在每次循环之后把加过的值减掉就可以绕过memset了. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits>

[BestCoder Round #4] hdu 4932 Miaomiao&#39;s Geometry (贪心)

Miaomiao's Geometry Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 363    Accepted Submission(s): 92 Problem Description There are N point on X-axis . Miaomiao would like to cover them ALL by

[BestCoder Round #3] hdu 4907 Task schedule (模拟简单题)

Task schedule Problem Description 有一台机器,并且给你这台机器的工作表,工作表上有n个任务,机器在ti时间执行第i个任务,1秒即可完成1个任务. 有m个询问,每个询问有一个数字q,表示如果在q时间有一个工作表之外的任务请求,请计算何时这个任务才能被执行. 机器总是按照工作表执行,当机器空闲时立即执行工作表之外的任务请求. Input 输入的第一行包含一个整数T, 表示一共有T组测试数据. 对于每组测试数据: 第一行是两个数字n, m,表示工作表里面有n个任务,

[BestCoder Round #4] hdu 4931 Happy Three Friends

Happy Three Friends Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 70    Accepted Submission(s): 62 Problem Description Dong-hao , Grandpa Shawn , Beautful-leg Mzry are good friends. One day ,

Bestcoder round #65 &amp;&amp; hdu 5592 ZYB&#39;s Premutation 线段树

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 175    Accepted Submission(s): 74 Problem Description ZYB has a premutation P,but he only remeber the reverse log of each prefix of the premutat

Bestcoder round #65 &amp;&amp; hdu 5593 ZYB&#39;s Tree 树形dp

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 354    Accepted Submission(s): 100 Problem Description ZYB has a tree with N nodes,now he wants you to solve the numbers of nodes distanced no m

HDU 4909 String(组合数学)

HDU 4909 String 题目链接 题意:给定一个字符串全是小写字符,可能有一个位置为?,问号可以替代任何字符,也可以删掉,问有多少连续字串满足所有字母是偶数个 思路:组合数学,计算所有前最串的各个字母的奇偶状态,用一个01串表示,然后记录下个数,对于每个相同的状态,任选两个就能得到一个子序列,答案为所有C(num, 2)的和. 但是这个问题多了一个?的情况,但是没关系,可以枚举?,然后把序列分为3部分去考虑,?之前,?之后,和包含了?的串分开考虑即可 代码: #include <cstd

hdu 4909 String(计数)

题目链接:hdu 4909 String 题目大意:给定一个字符串,由小写字母组成,最多包含一个问号,问号可以表示空或者任意一个字母.问有多少个子串,字母出现的次数均为偶数. 解题思路:因为最多又26个字母,对应每个字母的奇数情况用1表示,偶数情况用0.将一个前缀串表示成一个二进制数.然后对于每种相同的数s,任选两个即为一种可行子串(组合数学). 接着对于有问号的情况枚举一下问号替代的字符,然后对于问号后面的状态都要再加上一个该字符.这时计算个数时就要将前后分开讨论了. 这题交C++,结果卡FS