[2018雅礼省选集训3-30]program

注意到程序的运行是连续的,所以假设序列最左端左边还有一个 > > (且不能删除),那么一个区间子程序运行的过程一定时整个程序运行过程的一个子段。于是只需要用链表模拟一边总程序,再求出子段的开始和结束时间,直接用前缀和减一下即可。
fi表示指针第一次从 i1 i − 1 移动到 i i 的时间,gi表示指针第一次从 i i 移动到i1的时间,那么 [l,r] [ l , r ] 对应的子段开始时间就是 fl f l ,结束时间就是 min(fr+11,gl) min ( f r + 1 − 1 , g l )
f f 直接记录即可,但考虑到某些位置还没有从右向左走过就被删除了,会导致某些gi记录不到,我们只要删除 i i 的时候先标记下,等记录过gi之后再真正删去即可。
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 200010
using namespace std;
int n,q,b[N],ans[N*10][10],to[2][N],f[N],g[N],tim;
char cs[N];
bool ex[N];
int read()
{
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
int main()
{
    n=read();q=read();
    scanf("%s",cs+1);
    for(int i=1;i<=n;i++)
        if(cs[i]=='<') b[i]=-2;
        else if(cs[i]=='>') b[i]=-1;
        else b[i]=cs[i]-'0';
    b[0]=-1;    
    memset(ans,0,sizeof(ans));
    memset(f,0x3f,sizeof(f));
    memset(g,0x3f,sizeof(g));           
    int v=1,pos=1,lst=1;f[1]=tim=1;

    for(int i=0;i<=n;i++)
        ex[i]=1,to[0][i]=i-1,to[1][i]=i+1;
    to[1][0]=1; 
    while(pos<=n)
    {
        if(ex[pos])
        {
            if(b[pos]>=0) 
            {
                ans[tim][b[pos]]++;
                if(b[pos]>0) b[pos]--;else ex[pos]=0;
            }
            if(b[pos]<0) v=b[pos]+2;
        }

        if(!v) 
        {
            g[pos]=min(g[pos],tim);
            if(!ex[pos]) to[1][to[0][pos]]=to[1][pos],to[0][to[1][pos]]=to[0][pos];
        }
        pos=to[v][pos];

        if(!ex[pos]) continue;
        ++tim;

        memcpy(ans[tim],ans[tim-1],sizeof(ans[tim]));
        if(v) f[pos]=min(f[pos],tim);
        if(lst&&b[lst]<0&&b[pos]<0) ex[lst]=0;  
        lst=pos;
    }
    f[n+1]=tim;
    while(q--)
    {   
        int l=read(),r=read();
        for(int i=0;i<=9;i++)
            printf("%d ",ans[min(f[r+1]-1,g[l])][i]-ans[f[l]-1][i]);
        puts("");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值