BZOJ4866: [Ynoi2017]由乃的商场之旅 莫队

http://www.lydsy.com/JudgeOnline/problem.php?id=4866
询问一个字符串区间内有多少子区间重排后能形成回文串。
由于字符集只有26,可以给每个字母分配一个2的幂次作为权值,则相当于询问区间异或和是否为2的幂次或0
直接很难维护,那么考虑莫队,维护一个桶记录当前区间内所有前缀的异或和,若在前端插入删除则打上全局标记,然后每次插入删除时枚举每个2的幂次更新答案即可。时间复杂度n*sqrt(n)*26
还是那句话,BZOJ机子太慢,本地跑得游刃有余,交上去就过不了。。。
那么考虑卡卡常,若字符集小则复杂度低,若字符集大则答案小,那么预处理出以每个点开头或结尾,第一个合法的另一端在哪里,更新答案时若不可能有贡献就直接跳过,这样就可通过了。

#include
#include
#include
#include
#define gm 60005
using namespace std;
typedef long long ll;
struct Istream
{
    static const size_t str=1<<16;
    char buf[str],*s,*t;
    Istream():buf(),s(),t(){}
    char get()
    {
        return (s==t)?(t=buf+fread(s=buf,1,str,stdin),*s++):(*s++);
    }
    Istream& operator>> (int &x)
    {
        x=0; register char c;
        do c=get(); while(c<'0'||c>'9');
        while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-'0',c=get();
        return *this;
    }
    Istream& operator>> (char *s)
    {
        register char c;
        do c=get(); while(c<'a'||c>'z');
        while(c>='a'&&c<='z') *s++=c,c=get();
        return *this;
    }
}cin;
struct Ostream
{
    static const size_t str=1<<16;
    char buf[str],*s,*t;
    Ostream():buf(),s(buf),t(buf+str){}
    ~Ostream(){fwrite(buf,1,s-buf,stdout);}
    void put(char c)
    {
        (s==t)?(fwrite(s=buf,1,str,stdout),*s++=c):(*s++=c);
    }
    Ostream& operator<< (ll x)
    {
        if(!x) return operator<<('0');
        int a[22],t=1;
        while(x) a[t++]=x%10,x/=10;
        while(--t) put(a[t]+'0');
        return *this;
    }
    Ostream& operator<< (char c){return put(c),*this;}
}cout;
const char endl='\n';
int n,m,size;
int pre[gm],nex[gm];
char s[gm];
int t[gm];
ll ans[gm];
struct query
{
    int l,r;
    ll* ptr;
    bool operator< (const query& ano) const
    {
        return l/size!=ano.l/size?l/sizeint l=1,r=0;
ll now=0;
unsigned short cnt[1<<26];
int mark=0;
int tot=0;
int a=0;
int val[128];
inline void append_front(int x)
{
    tot^=x; mark^=x; ++cnt[x^mark];
    if(nex[l]>r) ++now;
    else
    {
        now+=cnt[mark];
        for(int i=0;i1<inline void contract_front(int x)
{
    if(nex[l-1]>r) --now;
    else
    {
        for(int i=0;i1<inline void append_back(int x)
{
    tot^=x; ++cnt[mark];
    if(pre[r]else
    {
        now+=cnt[tot^mark];
        for(int i=0;i1<inline void contract_back(int x)
{
    --cnt[tot^mark]; ++cnt[mark];
    if(pre[r+1]else
    {
        for(int i=0;i1<int main()
{
    cin>>n>>m>>(s+1);
    for(int i=1;i<=n;++i)
    {
        int c=s[i];
        if(!val[c]) val[c]=1<<(a++);
        t[i]=val[c];
    }
    int last=0; memset(cnt,0,sizeof cnt);
    for(int i=1;i<=n;++i)
    {
        int kre=last^t[i];
        pre[i]=cnt[kre];
        for(int j=0;jint pos=cnt[kre^(1<if(pos>pre[i]) pre[i]=pos;
        }
        cnt[last]=i; last=kre;
    }
    last=0; memset(cnt,0,sizeof cnt);
    for(int i=n;i>=1;--i)
    {
        int kre=last^t[i];
        nex[i]=(cnt[kre])?(cnt[kre]):n+1;
        for(int j=0;jint pos=cnt[kre^(1<if(!pos) pos=n+1;
            if(possqrt(n*a);
    for(int i=1;i<=m;++i)
    {
        cin>>q[i].l>>q[i].r;
        q[i].ptr=ans+i;
    }
    sort(q+1,q+m+1);
    memset(cnt,0,sizeof cnt);
    for(int i=1;i<=m;++i)
    {
        int x=q[i].l,y=q[i].r;
        while(xwhile(y>r) append_back(t[++r]);
        while(x>l) contract_front(t[l++]);
        while(yfor(int i=1;i<=m;++i) cout<return 0;
}

你可能感兴趣的:(莫队,BZOJ做题纪录)