JZOJ4645基因改造计划

Posted sadstone

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JZOJ4645基因改造计划相关的知识,希望对你有一定的参考价值。

Description

给出一个字符串和多组询问,每次询问一个区间内不同位置的回文串个数。

Solution

这里不是询问本质不同的回文串个数,不能用莫队+回文树。

考虑偶回文串较难处理,先在字符中间插入分隔符,变成长度为(2n+1)的串,用manacher处理得到以(i)为中心长度大于1的回文串个数(p_i),考虑原来的询问([l,r]),变成了新串上的([2l-1,2r+1]),设(L=2l-1)(R=2r+1),观察一下发现区间答案为:
[dfrac{1}{2}(r-l+1+sum_{i=L}^R min(p_i,i-L,R-i))]
(mid=dfrac{L+R}{2})
(i>mid)时((i<=mid)方法类似),需要求(sum_{i=mid+1}^Rmin(p_i,R-i))的值。
将所有询问离线,考虑一个位置(i)的值在(Rgeq i+p_i)(p_i),其余情况则时(R-i)(记这种情况为特殊位置)。(R)端点右移,遇到询问时统计一下特殊位置的个数与特殊位置上的(i)的和就可以计算出局部答案。

至于(i<=mid),把字符串倒过来再做一遍即可。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define fo(i,j,k) for(int i=j;i<=k;++i)
#define fd(i,j,k) for(int i=j;i>=k;--i)
using namespace std;
typedef long long ll;
const int N=3e5+10;
int f[N];
char s[N],a[N];
int tot=0;
void manacher(){
    int lm=0;
    int id,l=tot;
    for(int i=1;i<=l;i++){
        f[i]=lm>i?min(f[2*id-i],lm-i):1;
        while(a[i+f[i]]==a[i-f[i]]) f[i]++;
        if(f[i]+i>lm) lm=f[i]+i,id=i;
    }
    fo(i,1,l) f[i]--;
}
struct node{
    int l,r,mid,p;
}b[N];
int n,m;
ll an[N],cd[N];
bool cmp(node x,node y){
    return x.r<y.r;
}
struct tree{
    ll t,s,sf;
}tr[N<<1];
void update(int v){
    tr[v].t=tr[v<<1].t+tr[(v<<1)+1].t;
    tr[v].s=tr[v<<1].s+tr[(v<<1)+1].s;
    tr[v].sf=tr[v<<1].sf+tr[(v<<1)+1].sf;
}
void build(int v,int l,int r){
    if(l==r){
        tr[v].s=l,tr[v].t=1,tr[v].sf=0;
        return;
    }
    int mid=(l+r)>>1;
    build(v<<1,l,mid),build((v<<1)+1,mid+1,r);
    update(v);
}
void modify(int v,int l,int r,int x){
    if(l==r){
        tr[v].s=tr[v].t=0,tr[v].sf=f[x];
        return;
    }
    int mid=(l+r)>>1;
    x<=mid?modify(v<<1,l,mid,x):modify((v<<1)+1,mid+1,r,x);
    update(v);
}
int now;
ll sum(int v,int l,int r,int x,int y){
    if(l==x && r==y) return tr[v].sf+(ll)now*tr[v].t-tr[v].s;
    int mid=(l+r)>>1;
    if(y<=mid) return sum(v<<1,l,mid,x,y);
    else if(x>mid) return sum((v<<1)+1,mid+1,r,x,y);
    else return sum(v<<1,l,mid,x,mid)+sum((v<<1)+1,mid+1,r,mid+1,y);
}
vector<int> dl[N];
void solve(){
    build(1,1,tot);
    fo(i,1,tot) dl[i+f[i]].push_back(i);
    int p=0;
    fo(i,1,tot){
        now=i;
        int o=dl[i].size();
        fo(j,0,o-1) modify(1,1,tot,dl[i][j]);
        while(p<m && b[p+1].r==i){
            p++;
            an[b[p].p]+=sum(1,1,tot,b[p].mid,b[p].r);
            cd[b[p].p]=(b[p].r-b[p].l)/2;
        }
    }
    fo(i,1,tot) dl[i].clear();
}
int main()
{
    freopen("gene.in","r",stdin);
    freopen("gene.out","w",stdout);
    scanf("%d %d",&n,&m);
    scanf("%s",s+1);
    fo(i,1,n) a[++tot]=‘#‘,a[++tot]=s[i];
    a[++tot]=‘#‘;
    a[0]=‘*‘;
    manacher();
    fo(i,1,m){
        scanf("%d %d",&b[i].l,&b[i].r),b[i].p=i;
        b[i].l=2*b[i].l-1,b[i].r=2*b[i].r+1;
        b[i].mid=(b[i].l+b[i].r)/2;
    }
    sort(b+1,b+m+1,cmp);
    solve();
    reverse(f+1,f+tot+1);
    fo(i,1,m){
        int l=b[i].l,r=b[i].r;
        b[i].l=tot-r+1,b[i].r=tot-l+1;
        b[i].mid=(b[i].l+b[i].r)/2+1;
    }
    sort(b+1,b+m+1,cmp);
    solve();
    fo(i,1,m) printf("%lld
",(an[i]+cd[i])/2);
}




以上是关于JZOJ4645基因改造计划的主要内容,如果未能解决你的问题,请参考以下文章

Noi 十连测 基因改造计划

一次 Serverless 架构改造实践:基因样本对比

JZOJ 4722. 跳楼机

JZOJ 3894. 改造二叉树

[spfa][数论]JZOJ 4722 跳楼机

[spfa] Jzoj P4722 跳楼机