洛谷 P5640 【CSGRound2】逐梦者的初心

洛谷 P5640 【CSGRound2】逐梦者的初心

洛谷传送门

题目背景

注意:本题时限修改至250ms,并且数据进行大幅度加强。本题强制开启O2优化,并且不再重测,请大家自己重新提交。

由于Y校的老师非常毒瘤,要求zhouwc在csp考前最后3天参加期中考,zhouwc非常生气,决定消极考试,以涂完卡但全错为目标。现在retcarizy看zhouwc太可怜了,想要帮zhouwc解决一个问题,但他自己又太忙了,咕咕咕,于是就把问题甩给了你。

题目描述

给你一个长度为n的字符串S。

有m个操作,保证m\le nmn

你还有一个字符串T,刚开始为空。

共有两种操作。

第一种操作:

在字符串T的末尾加上一个字符。

第二种操作:

在字符串T的开头加上一个字符。

每次操作完成后要求输出有几个l \in [1,T.size]l∈[1,T.siz**e]满足以下条件:

对于\forall i \in [1,l]∀i∈[1,l]有T_{T.size-l+i} \ne S_{i}T**T.siz**el+i\=S**i

Tip:Tip:字符串下标从1开始。T.sizeT.siz**e表示T的长度。

输入格式

第一行两个正整数n,mn,m

第二行n个正整数,用空格隔开,第ii个整数表示S_iS**i

接下来mm行,每行两个数字opt,chopt,c**h,opt=0opt=0表示在T的末尾加一个字符chc**h,opt=1opt=1表示在T的开头加一个字符chc**h

输出格式

共mm行,每行一个非负整数表示第m操作后的输出。


题解:

很久之前打的模拟赛,今天刷状压重新刷到了这个。了债可。

记得当时打的70分做法,使用了双端队列。其实STL真是个好东西,能够比较简便地维护很多我们本需要手打大数据结构来维护的东西。打暴力程序的时候用它们也有很奇迹的效果。建议多学学。

时隔太久,有点忘记了双端队列的做法,但是思路就是大力模拟,应该很容易看懂。就直接放代码了。

70pts代码:

#include<cstdio>
#include<deque>
#include<vector>
using namespace std;
const int maxn=1e6+10;
int n,m;
int s[maxn];
bool flag;
char *p1,*p2,buf[100000];
#define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
int read()
{
    int x=0,f=1;
    char ch=nc();
    while(ch<48){if(ch=='-')f=-1;ch=nc();}
    while(ch>47)    x=(((x<<2)+x)<<1)+ch-48,ch=nc();
    return x*f;
}
deque<int> q;
vector<int> vec;
vector<int>::iterator it;
int main()
{
    n=read();m=read();
    for(int i=0;i<n;i++)
        s[i]=read();
    while(m--)
    {
        int opt=read();
        int x=read();
        if(opt)
        {
            q.push_front(x);
            flag=0;
            for(int i=0;i<q.size();i++)
                if(q[i]==s[i])
                {
                    flag=1;
                    break;
                }
            if(!flag)
                vec.push_back(q.size());
        }
        else
        {
            q.push_back(x);
            it=vec.begin();
            while(it!=vec.end())
            {
                (*it)++;
                if(s[*it-1]==x)
                    vec.erase(it);
                else    
                    ++it;
            }
            if(s[0]!=x)
                vec.push_back(1);
        }
        printf("%d\n",vec.size());
    }
    return 0;
}

然后考虑满分思路:

由于每个位置和每种字符都是独立的,对每种字符都记录一下位子。怎么记录呢?用\(f[i]=0/1\)表示长度为i的后缀可不可以,0表示可以,1表示不行。

于是bitset优化就比较明显了。

你看,又是bitset

在末尾加一个字符时,左移后做or运算。

在开头加一个字符时,直接or上该字符出现的状态左移长度减一位。

答案就是范围内0的个数。

满分代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int n,m,opt,s[maxn],dt;
bitset<35005> dp,id[1005],now;
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&s[i]);
	for(int i=1;i<=m;i++)
		id[s[i]].set(i);
	now.set();
	for(int i=1;i<=m;i++)
    {
		scanf("%d%d",&opt,&dt);
		now.reset(i);
		if(opt==0)
			dp=(dp<<1)|id[dt];
		else
			dp=dp|(id[dt]<<(i-1));
		printf("%d\n",(~(dp|now)).count());
	}
	return 0;
}
posted @ 2020-10-12 18:59  Seaway-Fu  阅读(112)  评论(0编辑  收藏  举报