题解 P5640 【【CSGRound2】逐梦者的初心】

zhouwc

2019-11-10 14:58:20

Solution

#### 官方题解 ##### subtask1 对于每次操作,枚举$l$,枚举$i$,判断一下。考察了循环语句和分支语句的简单应用。 时间复杂度$O(m^3)$ ##### subtask2 记录下每次操作后每个$i$满不满足条件。 考虑在末尾加一个字符 不难发现原来的$i$变成了现在的$i+1$,再把新加入的字符对状态的影响处理一下。 再考虑在开头加一个字符 原来的状态不用变,只要把新加入的字符对状态的影响处理。 时间复杂度$O(m^2)$ ##### subtask3 字符集非常小,答案只有在特殊情况下才存在,可能存在什么神奇的做法。 ##### subtask4 每个位子和每种字符都是独立的,对每种字符都记录一下位子。 用$f[i]=0 or 1$表示长度为$i$的后缀可不可以,0表示可以,1表示不行。 考虑f只有0和1,可以用bitset优化,对每种字符都开一个bitset记录是不是该字符。 在末尾加一个字符时,左移后做or运算。 在开头加一个字符时,直接or上该字符出现的状态左移长度减一位。 答案就是范围内0的个数。 复杂度$O(m^2/w)$ std: ```cpp #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<cstdlib> #include<bitset> using namespace std; int n,m,opt,S[1000005],dt; bitset<35005> f,id[1005],now; int read(){ int ans=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch<='9'&&ch>='0'){ ans=ans*10+ch-'0'; ch=getchar(); } return ans; } int main(){ n=read(); m=read(); for(int i=1;i<=n;i++) S[i]=read(); for(int i=1;i<=m;i++) id[S[i]].set(i); now.set(); for(int i=1;i<=m;i++){ opt=read(); dt=read(); now.reset(i); if(opt==0) f=(f<<1)|id[dt]; else f=f|(id[dt]<<(i-1)); printf("%d\n",(~(f|now)).count()); } return 0; } ``` 附录: ##### 关于如何使用bitset 简单的来说,bitset就是压位优化的0/1数组。 定义一个长度为$len$的bitset: ``` bitset<len> f; ``` 把f的每一位都改为1 ``` f.set(); ``` 把f的第i位改为1 ``` f.set(i); ``` 把f的每一位都改为0 ``` f.reset(); ``` 把f的第i位改为0 ``` f.reset(i); ``` 求f有几个1 ``` f.count(); ``` 各类位运算和整数类型一样 ``` f=f<<1; f=f>>1; f=f&f; f=f|f; f=f^f; f=~f; ```