首页 > 代码库 > hdu 4909 String (map + 状压)

hdu 4909 String (map + 状压)

题目大意:

给定一个可能含‘?’的字符串。然后问这个字符串有多少个子串是含有所有的字符都只出现两次。

其中‘?‘ 可以被替换成任意字符,也可以被remove...


思路分析:

这是bestcoder的round #3的第三题。

这道题的做法和 4908 的做法差不多。

我们把 ‘?’ 左右两边的状态分别处理出来。

然后用map 计数。然后枚举左边的状态。同时枚举? 对应的字符。

然后去寻找右边对应的状态,此时 ans 就可以加上答案。

注意的是要考虑到以 ? 结尾的情况。所以在 ? 的状态要和上一个相同。


#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#define maxn 20005

using namespace std;

char str[maxn];
int st[maxn];
map<int,int>lef;
map<int,int>rig;
map<int,int>mp;

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        lef.clear(),rig.clear(),mp.clear();

        scanf("%s",str+1);

        int pos=0;
        int len=strlen(str+1);

        for(int i=1;i<=len;i++)
        {
            if(str[i]=='?'){
                pos=i,st[i]=st[i-1];
            }
            else {
                st[i]=(st[i-1]^(1<<(str[i]-'a')));
            }
        }

        for(int i=0;i<=len;i++){
            mp[st[i]]++;
            if(pos && i<pos){
                lef[st[i]]++;
            }
            if(pos && i>=pos){
                rig[st[i]]++;
            }
        }
        int ans=0;
        if(pos){
            for(map<int,int>::iterator it = lef.begin();it!=lef.end();it++){
                int x=it->first;
                for(int j=0;j<26;j++){
                    int y=(x^(1<<j));
                    map<int,int>::iterator ct = rig.find(y);
                    if(ct!=rig.end())
                    {
                        ans+=(it->second)*(ct->second);
                    }
                }
            }
        }
        for(map<int,int>::iterator it = mp.begin();it!=mp.end();it++)
            ans+=(it->second*(it->second-1))/2;
        printf("%d\n",ans);
    }
    return 0;
}