洛谷 P5640 【CSGRound2】逐梦者的初心
洛谷 P5640 【CSGRound2】逐梦者的初心
题目背景
注意:本题时限修改至250ms,并且数据进行大幅度加强。本题强制开启O2优化,并且不再重测,请大家自己重新提交。
由于Y校的老师非常毒瘤,要求zhouwc在csp考前最后3天参加期中考,zhouwc非常生气,决定消极考试,以涂完卡但全错为目标。现在retcarizy看zhouwc太可怜了,想要帮zhouwc解决一个问题,但他自己又太忙了,咕咕咕,于是就把问题甩给了你。
题目描述
给你一个长度为n的字符串S。
有m个操作,保证m\le nm≤n。
你还有一个字符串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**e−l+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;
}