HDU 4909 String(组合数学)

HDU 4909 String

题目链接

题意:给定一个字符串全是小写字符,可能有一个位置为?,问号可以替代任何字符,也可以删掉,问有多少连续字串满足所有字母是偶数个

思路:组合数学,计算所有前最串的各个字母的奇偶状态,用一个01串表示,然后记录下个数,对于每个相同的状态,任选两个就能得到一个子序列,答案为所有C(num, 2)的和。

但是这个问题多了一个?的情况,但是没关系,可以枚举?,然后把序列分为3部分去考虑,?之前,?之后,和包含了?的串分开考虑即可

代码:

#include <cstdio>
#include <cstring>
#include <map>
using namespace std;

typedef int ll;

const int N = 20005;

int t, n, v, x;
char str[N];
map<int, int> hash;

int main() {
    scanf("%d", &t);
    while (t--) {
	scanf("%s", str);
	v = -1;
	n = strlen(str);
	for (int i = 0; i < n; i++) {
	    if (str[i] == '?') {
		v = i;
		break;
	    }
	}
	int ans = 0;
	if (v == -1) {
	    x = 0;
	    hash.clear();
	    hash[0]++;
	    for (int i = 0; i < n; i++) {
		x ^= (1<<(str[i] - 'a'));
		ans += hash[x];
		hash[x]++;
	    }
	    printf("%d\n", ans);
	    continue;
	}
	else {
	    hash.clear();
	    ans = 0;
	    x = 0;
	    hash[0]++;
	    for (int i = 0; i < v; i++) {
		x ^= (1<<(str[i] - 'a'));
		ans += hash[x];
		hash[x]++;
	    }
	    hash.clear();
	    x = 0;
	    hash[0]++;
	    for (int i = v + 1; i < n; i++) {
		x ^= (1<<(str[i] - 'a'));
		ans += hash[x];
		hash[x]++;
	    }
	    hash.clear();
	    x = 0;
	    hash[0]++;
	    for (int i = v + 1; i < n; i++) {
		x ^= (1<<(str[i] - 'a'));
		hash[x]++;
	    }
	    x = 0;
	    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)];
	    }
	    for (int i = v - 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;
}

HDU 4909 String(组合数学),布布扣,bubuko.com

时间: 2024-11-14 14:22:55

HDU 4909 String(组合数学)的相关文章

hdu 4909 String(计数)

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

[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 th

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>

hdu 6194 string string string(后缀数组)

题目链接:hdu 6194 string string string 题意: 给你一个字符串,给你一个k,问你有多少个子串恰好在原串中出现k次. 题解: 后缀数组求出sa后,用height数组的信息去找答案. 每次用k长度的区间去卡height数组,求出该区间的lcp. 该区间的贡献就是ans=lcp-max(height[i],height[i+k]). 如果ans<=0,就不贡献. 比如 2 aaa 后缀数组为: 1 a 2 aa 3 aaa height为 0,1,2 现在扫到[1,2],

hdu 4821 String(字符串hash)

题目链接:hdu 4821 String 题意: 给你一个字符串,问你有多少子串,满足长度为m*len,并且这个子串能分成m个len长度的不同串. 题解: BKDRhash+map来判重.注意的是要以len长分类来扫,这样才不会超时. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=a;i<=b;++i) 3 using namespace std; 4 typedef unsigned long long ull; 5 co

HDU 2476 String painter(字符串转变)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2476 题意:给定两个长度相同的串A和B.每次操作可以将A的连续一段改变为另一个字母.求将A转换成B最少需要多少次操作? 思路:首先,我们假设没有A串,那么这就跟 BZOJ1260是一样的了,即答案为DFS(0,n-1)...但是这里有了A串就有可能使得操作次数更少.因为可能有些对应位置字母是相同的.我们设 ans[i]表示前i个字母变成一样的,那么若A[i]=B[i]则ans[i]=ans[i-1]

hdu 3374 String Problem (kmp+最大最小表示法)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3374 题目大意:输出最大和最小的是从哪一位开始的,同时输出最小循环节的个数. 这里简单介绍对字符串最小表示的方法: (1)  利用两个指针p1, p2.初始化时p1指向s[0], p2指向s[1]. (2)  k = 0开始,检验s[p1+k] 与 s[p2+k] 对应的字符是否相等,如果相等则k++,一直下去,直到找到第一个不同,(若k试了一个字符串的长度也没找到不同,则那个位置就是最小表示位置,

HDU 4159 Indomie ( 组合数学 )

HDU 4159 Indomie ( 组合数学 ) #include <cstdio> typedef __int64 LL; #define MAXN 101 int n, s; LL po[ MAXN ]; void init() { po[0] = 1; for( int i = 1; i < MAXN; ++i ) po[i] = po[i-1] * 2; } double CC( int n, int m ) { double res = 1; for( int i = 0;