Uva 6284 Hyperdrome

来源:互联网 发布:java版波斯王子2下载 编辑:程序博客网 时间:2024/05/21 21:36

给一串长度为n的字符串,求一共有多少个子串重排后可为回文串。n为3*10^5,字符集为大写字母和小写字母。

我尝试再现一下思路...

首先,子串一定是一个串的某个前缀的后缀(涨姿势),所以子串共有n(n-1)/2个。

其次,一个回文串一定满足:1.当回文串长为奇数时,该串中只有一种字符数量为奇数,其他字符数量全部为偶数。2.当回文串长度为偶数时,所有出现的字符数量都为偶数。存储一个串的奇偶性可以利用位存储的方式存储其状态mask,字符集大小为52,所以需要52位来,longlongint即可满足。如某子串状态为mask,该子串=前缀2-前缀1.则有mask = mask2^mask1.

如果直接暴力的话,那么复杂度是为o(n^2*52)。显然不行。

事实上,我们无需与每一个前缀均异或运算,因为很多子串都是不满足条件的,这里就可以用状态压缩去除很多废情况。首先,用哈希存储一下每一个前缀的mask出现过多少次,对于当前的状态,只有之前的前缀状态相同,或者异或后有一位为1(状压枚举),才满足条件,这样的话就可以利用哈希去查找合法情况。这里有一个细节,就是如果当前状态就为回文串,也需要加到答案里面。因为字符集为52,已经超过int表示范围,所以在位运算的时候要将1强制转换为long long int型,否则会出错。

考虑周全以后1y,感觉也是对今天wa了一下午加一晚上的一种安慰吧...

#include <iostream>#include <stdio.h>#include <string.h>using namespace std;#define N 1000007#define MAXN 300005#define LL long longint head[N],nn;typedef struct{    LL num,key;    int next;}node;node ele[N];char inp[MAXN];LL save[MAXN];int ret(char a){    if(a>='a'&&a<='z') return (a-'a');    else{        return (26+a-'A');    }}void Insert(LL tmp){     LL x;     x=tmp%N;     for(int i=head[x];~i;i=ele[i].next){        if(ele[i].key==tmp) {            ele[i].num++;            return ;        }     }        ele[nn].num=1;        ele[nn].key=tmp;        ele[nn].next=head[x];        head[x]=nn++;}LL Search(LL tmp){     LL x;     x=tmp%N;     for(int i=head[x];~i;i=ele[i].next){        if(ele[i].key==tmp){            return ele[i].num;        }     }     return 0;}int main(){    int n;    while(~scanf("%d",&n)){        LL ans=0;        nn=0;        memset(head,-1,sizeof(head));        scanf("%s",inp);        LL tmp=0;        for(int i=0;i<n;i++){            tmp^=((LL)1<<ret(inp[i]));            Insert(tmp);            if(tmp==0) ans++;            ans+=Search(tmp)-1;            if(i%2==0){                int cnt=0;                for(int j=0;j<52;j++){                    if(tmp&((LL)1<<j)) cnt++;                    if(cnt>1) break;                }                if(cnt==1) ans++;            }            for(int j=0;j<52;j++){                ans+=Search(tmp^((LL)1<<j));            }        }        printf("%lld\n",ans);    }    return 0;}


0 0
原创粉丝点击