hdu4909 状态压缩(偶数字符子串)
生活随笔
收集整理的這篇文章主要介紹了
hdu4909 状态压缩(偶数字符子串)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題意:
? ? ? 給你一個字符串,里面最多有一個'?','?'可以表示'a' - 'z',也可以什么都不表
示,這里要明確,什么都不表示不是不存在的意思,當aa什么都不表示的時候aa 也不等于aa? ,因為這個wa的快吐血了,題目要求輸出一共有多少個子串滿足所有字母('a' -'z')出現的次數必須是偶數個。
思路:
? ? ? 給你一個字符串,里面最多有一個'?','?'可以表示'a' - 'z',也可以什么都不表
示,這里要明確,什么都不表示不是不存在的意思,當aa什么都不表示的時候aa 也不等于aa? ,因為這個wa的快吐血了,題目要求輸出一共有多少個子串滿足所有字母('a' -'z')出現的次數必須是偶數個。
思路:
? ? ? 首先對于每一個前綴串的奇偶狀態我們可以用mark[1<<26]的狀態壓縮表示,如果當前字母的個數是偶數,那么對應位置的狀態就是0,奇數是1,先不考慮'?',假如當前的這個狀態在之前出現過,那么當前可以增加的子串數量就是當前狀態之前出現的次數,為什么是這樣呢?兩個相同的狀態之間肯定是經過了偶數次變化,奇數 + 偶數 = 奇數,偶數 +?偶數 = 偶數,所以說前面有多少個當前狀態,就有多少個偶數間隔,就會有幾個滿足題意的子串,(也可以全求出來,然后排列組合C(m,2))一個意思,現在在把'?'考慮進來,先算出沒意義的情況,然后在枚舉他是'a' - 'z',枚舉的時候我是先枚舉一遍以'?'結尾的,然后對于?后面的直接就把每一個狀態的每一位都改變一次,求出所有的和就行了,還有要注意的一點就是mark[1<<26]數組很大,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; }
總結
以上是生活随笔為你收集整理的hdu4909 状态压缩(偶数字符子串)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hdu2492 数状数组或者线段树
- 下一篇: hdu4908 中位数子串