[bzoj4866] [Ynoi2017]由乃的商场之旅

来自FallDream的博客,未经允许,请勿转载,谢谢,


由乃有一天去参加一个商场举办的游戏。商场派了一些球王排成一行。每个人面前有几堆球。说来也巧,由乃和你一样,觉得这游戏很无聊,于是决定换一个商场。另一个商场是Deus的,他看到由乃来了,于是想出了一个更有趣的游戏:写数据结构题这个题是这样的:
我们的情人,不过是随便借个名字,用幻想吹出来的肥皂泡,把信拿去吧,你可以使假戏成真。我本来是无病呻吟,漫无目的的吐露爱情---现在这些漂泊不定的鸟儿有地方栖息了,你可以从信里看出来。拿去吧---由于不是出自真心,话就说得格外动听,拿去吧,就这么办吧...由于世界会在7月20日完结,作为救世主,间宫卓司要在19日让
所有人回归天空现在已经是19日傍晚,大家集合在C栋的天台上,一共n个人在他们面前,便是终之空,那终结的天空
回归天空是一件庄重的事情,所以卓司决定让大家分批次进行,给每个人给了一个小写字母'a'->'z'作为编号一个区间的人如果满足他们的编号重排之后可以成为一个回文串,则他们可以一起回归天空,即这个区间可以回归天空由于卓司是一个喜欢妄想的人,他妄想了m个区间,每次他想知道每个区间中有多少个子区间可以回归天空因为世界末日要来了,所以卓司的信徒很多
由乃天天做数据结构已经快恶心死了,于是让您帮她做当然,您天天做数据结构题,肯定也觉得恶心死了,不过可爱即正义!所以这个题还是要做的~
 
n,m<=60000  2s,166MB
 
把a-z编号成2的次幂,求出前缀异或和,那么对于每一个位置,和他能组成可行区间的前缀异或和和它最多只有一个二进制位不同。
很容易想到莫队算法+枚举二进制位查询的方法,复杂度$O(26n\sqrt{n})$  并不能通过这道题。
但是有个treat,就是发现不同的前缀异或和不是很多,所以考虑离散,预处理每一个能转移到的所有状态,这样就把转移的复杂度从$O(26)$降到了$O(玄学)$  233 而且居然跑的飞快,直接跑到了rank5  但是估计是可以被叉掉的。
但是有没有科学的做法?当然有。对于每个点,预处理它到所在的块的右端点的答案。莫队的时候从右端点开始扩展。最后,枚举左边那个不完整的部分统计答案即可。
块的大小是k的情况下,复杂度是$\frac{n^{2}26}{k}+nk$ , k=$\sqrt{26n}$的时候复杂度是$O(n\sqrt{26n})$ 然而跑了20s快t了..
加上前面的那个优化,可以在5s左右跑完
乱搞
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#define rint register int
#define MN 60000
#define ll long long
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}

map<int,int> mp;
ll ans=0,Ans[MN+5];
bool b[MN+5];
int n,m,now=0,dn=0,p[27],block[MN+5],size,L,R,ha[MN+5],cnt=0,f[MN+5],head[MN+5];
char st[MN+5];
struct ques{int l,r,id;}q[MN+5];
struct edge{int to,next;}e[MN*27+5];
bool cmp(ques x,ques y){return block[x.l]==block[y.l]?x.r<y.r:x.l<y.l;}
inline void ins(int f,int t){if(!t)return;e[++cnt]=(edge){t,head[f]};head[f]=cnt;}

inline void Ins(int num,int ad)
{
    for(int i=head[ha[num]];i;i=e[i].next)
        ans+=f[e[i].to]*ad;
    ans+=ad*f[ha[num]];
}

int main()
{
    n=read();m=read();p[0]=1;size=sqrt(n);
    for(rint i=1;i<=n;++i) block[i]=(i-1)/size+1;
    for(rint i=1;i<26;++i) p[i]=p[i-1]<<1;
    scanf("%s",st+1);mp[0]=++dn;
    for(rint i=1;i<=n;++i) ha[i]=ha[i-1]^p[st[i]-'a'],!mp[ha[i]]?mp[ha[i]]=++dn:b[i]=1;
    for(rint j=0;j<26;++j) ins(1,mp[p[j]]);ha[0]=1;
    for(int i=1;i<=n;++i)
    {
        int now=mp[ha[i]];
        if(!b[i])for(int j=0;j<26;++j) ins(now,mp[ha[i]^p[j]]);
        ha[i]=now;
    }
    for(rint i=1;i<=m;++i) q[i].l=read(),q[i].r=read(),q[i].id=i;
    sort(q+1,q+m+1,cmp);L=R=1,++f[1],++f[ha[1]],ans=1;
    for(rint i=1;i<=m;++i)
    {
        while(R<q[i].r) ++R,Ins(R,1),++f[ha[R]];
        while(L>q[i].l) --L,Ins(L-1,1),++f[ha[L-1]];
        while(L<q[i].l) --f[ha[L-1]],Ins(L-1,-1),++L;
        while(R>q[i].r) --f[ha[R]],Ins(R,-1),--R;
        Ans[q[i].id]=ans;
    }
    for(int i=1;i<=m;++i) printf("%lld\n",Ans[i]);
    return 0;
}
View Code
科学 但是成功贴着时限跑过去
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define rint register int
#define MN 60000
#define MB 1300
#define ll long long
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}

ll ans=0,Ans[MN+5],Pre[MN+5];
int n,m,now=0,dn=0,p[27],block[MN+5],size,R,ha[MN+5],tot,rt[MB+5];
unsigned short f[1<<26];
char st[MN+5];
struct ques{int l,r,id;}q[MN+5];
bool cmp(ques x,ques y){return block[x.l]==block[y.l]?x.r<y.r:x.l<y.l;}

inline void Ins(int num,int ad)
{
    if(num>n) return;
    f[num=ha[num]]+=ad;
    for(int i=0;i<26;++i) f[num^p[i]]+=ad;
}

ll Bl(int l,int r)
{
    ll ans2=0;
    for(int i=l;i<=r;++i)
        Ins(i-1,1),ans2+=f[ha[i]];
    for(int i=l;i<=r;++i) Ins(i-1,-1);
    return ans2;
}

int main()
{
    n=read();m=read();p[0]=1;size=sqrt(26*n);tot=(n-1)/size+1;
    for(rint i=1;i<=n;++i) block[i]=(i-1)/size+1;
    for(rint i=1;i<26;++i) p[i]=p[i-1]<<1;
    scanf("%s",st+1);
    for(rint i=1;i<=n;++i) ha[i]=ha[i-1]^p[st[i]-'a'];
    for(int i=1;i<=tot;++i)
    {
        rt[i]=min(n,i*size);ans=0;
        for(int j=rt[i];j>rt[i-1];--j)
            Ins(j,1),ans+=f[ha[j-1]],Pre[j]=ans;
        for(int j=rt[i];j>rt[i-1];--j) Ins(j,-1);
    }
    for(rint i=1;i<=m;++i) q[i].l=read(),q[i].r=read(),q[i].id=i;
    sort(q+1,q+m+1,cmp);
    for(rint i=1,last=0;i<=m;++i)
    {
        if(block[q[i].l]!=last)
        {
            for(int i=rt[last];i<R;++i) Ins(i,-1);
            last=block[q[i].l];Ins(R=rt[last],1);ans=(++R<=n);
        }
        if(block[q[i].l]==block[q[i].r]) Ins(rt[last],-1),Ans[q[i].id]=Bl(q[i].l,q[i].r),Ins(rt[last],1);
        else
        {
            while(R<q[i].r) ++R,Ins(R-1,1),ans+=f[ha[R]];
            ll ans2=0;Ins(R,1);Ins(rt[last],-1);
            for(int j=q[i].l;j<=rt[last];++j) ans2+=f[ha[j-1]];
            Ans[q[i].id]=ans+Pre[q[i].l]+ans2;
            Ins(R,-1);Ins(rt[last],1);
        }
    }
    for(int i=1;i<=m;++i) printf("%lld\n",Ans[i]);
    return 0;
}
View Code

把它们揉一起  飞快

#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
#include<cmath>
#define rint register int
#define MN 60000
#define MB 1300
#define ll long long
using namespace std;
inline int read()
{
    int x = 0 , f = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x * f;
}

bool b[MN+5];
map<int,int> mp;
ll ans=0,Ans[MN+5],Pre[MN+5];
int n,m,now=0,dn=0,p[27],block[MN+5],size,R,ha[MN+5],tot,rt[MB+5],head[MN+5],cnt=0;
unsigned short f[MN+5];
char st[MN+5];
struct ques{int l,r,id;}q[MN+5];
struct edge{int to,next;}e[MN*27+5];
bool cmp(ques x,ques y){return block[x.l]==block[y.l]?x.r<y.r:x.l<y.l;}
inline void ins(int f,int t){if(!t)return;e[++cnt]=(edge){t,head[f]};head[f]=cnt;}
inline void Ins(int num,int ad)
{
    if(num>n) return;
    f[num=ha[num]]+=ad;
    for(int i=head[num];i;i=e[i].next) f[e[i].to]+=ad;
}

ll Bl(int l,int r)
{
    ll ans2=0;
    for(int i=l;i<=r;++i)
        Ins(i-1,1),ans2+=f[ha[i]];
    for(int i=l;i<=r;++i) Ins(i-1,-1);
    return ans2;
}

int main()
{
    n=read();m=read();p[0]=1;size=sqrt(26*n);tot=(n-1)/size+1;
    for(rint i=1;i<=n;++i) block[i]=(i-1)/size+1;
    for(rint i=1;i<26;++i) p[i]=p[i-1]<<1;
    scanf("%s",st+1);mp[0]=++dn;
    for(rint i=1;i<=n;++i) ha[i]=ha[i-1]^p[st[i]-'a'],!mp[ha[i]]?mp[ha[i]]=++dn:b[i]=1;
    for(rint j=0;j<26;++j) ins(1,mp[p[j]]);ha[0]=1;
    for(int i=1;i<=n;++i)
    {
        int now=mp[ha[i]];
        if(!b[i])for(int j=0;j<26;++j) ins(now,mp[ha[i]^p[j]]);
        ha[i]=now;
    }
    for(int i=1;i<=tot;++i)
    {
        rt[i]=min(n,i*size);ans=0;
        for(int j=rt[i];j>rt[i-1];--j)
            Ins(j,1),ans+=f[ha[j-1]],Pre[j]=ans;
        for(int j=rt[i];j>rt[i-1];--j) Ins(j,-1);
    }
    for(rint i=1;i<=m;++i) q[i].l=read(),q[i].r=read(),q[i].id=i;
    sort(q+1,q+m+1,cmp);
    for(rint i=1,last=0;i<=m;++i)
    {
        if(block[q[i].l]!=last)
        {
            for(int i=rt[last];i<R;++i) Ins(i,-1);
            last=block[q[i].l];Ins(R=rt[last],1);ans=(++R<=n);
        }
        if(block[q[i].l]==block[q[i].r]) Ins(rt[last],-1),Ans[q[i].id]=Bl(q[i].l,q[i].r),Ins(rt[last],1);
        else
        {
            while(R<q[i].r) ++R,Ins(R-1,1),ans+=f[ha[R]];
            ll ans2=0;Ins(R,1);Ins(rt[last],-1);
            for(int j=q[i].l;j<=rt[last];++j) ans2+=f[ha[j-1]];
            Ans[q[i].id]=ans+Pre[q[i].l]+ans2;
            Ins(R,-1);Ins(rt[last],1);
        }
    }
    for(int i=1;i<=m;++i) printf("%lld\n",Ans[i]);
    return 0;
}
View Code
posted @ 2017-05-20 23:57  FallDream  阅读(285)  评论(0编辑  收藏  举报