hdu4909 状态压缩(偶数字符子串)
? ? ? 給你一個字符串,里面最多有一個'?','?'可以表示'a' - 'z',也可以什么都不表
示,這里要明確,什么都不表示不是不存在的意思,當aa什么都不表示的時候aa 也不等于aa? ,因為這個wa的快吐血了,題目要求輸出一共有多少個子串滿足所有字母('a' -'z')出現(xiàn)的次數(shù)必須是偶數(shù)個。
思路:
? ? ? 首先對于每一個前綴串的奇偶狀態(tài)我們可以用mark[1<<26]的狀態(tài)壓縮表示,如果當前字母的個數(shù)是偶數(shù),那么對應(yīng)位置的狀態(tài)就是0,奇數(shù)是1,先不考慮'?',假如當前的這個狀態(tài)在之前出現(xiàn)過,那么當前可以增加的子串數(shù)量就是當前狀態(tài)之前出現(xiàn)的次數(shù),為什么是這樣呢?兩個相同的狀態(tài)之間肯定是經(jīng)過了偶數(shù)次變化,奇數(shù) + 偶數(shù) = 奇數(shù),偶數(shù) +?偶數(shù) = 偶數(shù),所以說前面有多少個當前狀態(tài),就有多少個偶數(shù)間隔,就會有幾個滿足題意的子串,(也可以全求出來,然后排列組合C(m,2))一個意思,現(xiàn)在在把'?'考慮進來,先算出沒意義的情況,然后在枚舉他是'a' - 'z',枚舉的時候我是先枚舉一遍以'?'結(jié)尾的,然后對于?后面的直接就把每一個狀態(tài)的每一位都改變一次,求出所有的和就行了,還有要注意的一點就是mark[1<<26]數(shù)組很大,memset清不起,我們要采取每次只把用過的清空的原則去減少時間。感覺沒說清楚,但這個題目不是很好說明白,自己做了將近一天才AC,要是看不懂就看看代碼然后自己在想想吧。
#include<stdio.h> #include<string.h> int sum[(1<<26)+10]; int num[22000]; char str[22000];int main () {int i ,j ,t ,ans;scanf("%d" ,&t);while(t--){scanf("%s" ,str);int len = strlen(str);int mki = -1 ,tt = 0;num[0] = 0;sum[num[0]] = 1;for(ans = i = 0 ;i < len ;i ++){if(str[i] == '?') {mki = i;ans += sum[num[tt]];sum[num[tt]] ++;continue;}tt ++;num[tt] = num[tt-1] ^ (1 << (str[i] - 'a'));ans += sum[num[tt]]; sum[num[tt]] ++;}for(i = 0 ;i <= tt ;i ++)sum[num[i]] = 0; if(mki == -1){printf("%d\n" ,ans);continue;}tt = 0;num[0] = 0;sum[num[0]] = 1;for(i = 0 ;i < mki ;i ++){tt ++;num[tt] = num[tt-1] ^ (1 << (str[i] - 'a'));sum[num[tt]] ++;}for(i = 'a' ;i <= 'z' ;i ++){int tmp = num[tt] ^ (1 << (i - 'a'));ans += sum[tmp];}for(i = mki + 1 ;i < len ;i ++){tt ++;num[tt] = num[tt-1] ^ (1 << (str[i] - 'a'));for(j = 0 ;j < 26 ;j ++)ans += sum[num[tt]^(1<<j)]; }for(int i = 0 ;i <= tt ;i ++)sum[num[i]] = 0; printf("%d\n" ,ans);}return 0; }
總結(jié)
以上是生活随笔為你收集整理的hdu4909 状态压缩(偶数字符子串)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hdu2492 数状数组或者线段树
- 下一篇: hdu4908 中位数子串