题目传送门
淦,这道题TLE了不知道多少次呜呜呜
这道题呢首先你得看数据范围,因此下面的代码
O
(
n
)
O(n)
O(n)的时间复杂度你肯定过不了!
#include<iostream>
#include<stack>
using namespace std;
char a[2102100];
int ans[2102020];
int main(){
int T;
cin>>T;
while(T--){
int s;
cin>>s;
char u;
int uu=0;
char t='9';
getchar();
int p=1;
for(int i=1;i<=s;i++){
scanf("%c",&u);
if(t==u&&p){
ans[i]=++uu;
a[++uu]=u;
t=u;
}else{
p=0;
int ju=1;
for(int j=1;j<=uu;j++){
// printf("a[%d]===>%c u===>%c\n",j,a[j],u);
if(a[j]!=u){
ans[i]=j;
a[j]=u;
ju=0;
break;
}
}
if(ju){
a[++uu]=u;
ans[i]=uu;
}
t=u;
}
}
cout<<uu<<endl;
for(int i=1;i<=s;i++){
a[i]='9';
printf("%d ",ans[i]);
}
printf("\n");
}
return 0;
}
这一串TLE的代码的大致思路就是你记录一下数组的尾部都是什么字符,然后找互斥的情况。
但是一旦数据是
111111111111111111111111111111111111111
…
…
111111111111111111111111111111111111111……
111111111111111111111111111111111111111……那么最后坏的情况就出现了,因此一定会被卡。
那么怎么做呢?每一个字符字串的最后一位一定是和我们输入的字符不一样我才能将这个字符插入到子串的后边,因此,确实应该把每一个已知子串的最后一位记录下来,那么怎么优化上述代码?
首先我们想,加入
u
=
′
1
′
u='1'
u=′1′,那么我只需要找到一个子串的末尾一位为0的子串编号就行了,然而我们遍历的过程万一之前都是1结尾的子串,那么这一段时间我们就浪费了,因此,可以开一个数组记录一下子串末尾是0的子串编号,(当然再开一个int a00记录一下这个一共有多少哈哈哈),那么(处理方式类似于
s
t
a
c
k
stack
stack)每一次
a
00
−
−
a00--
a00−−,(也就是遍历到这里了以后这一编号的子串的最后一位就变成了1,同理再让a11++),那么
u
=
′
0
′
u='0'
u=′0′这个情况也就类似了。
下面是非TLE的AC代码
#include<iostream>
#include<stack>
using namespace std;
char a[2102100];
int ans[2102020];
int a0[210210];
int a1[210210];
int main(){
int T;
cin>>T;
while(T--){
int s;
cin>>s;
char u;
int num=0,a11=0,a00=0;
getchar();
for(int i=1;i<=s;i++){
scanf("%c",&u);
if(u=='0'){
if(a11>=1) {
int number=a1[a11--];
a0[++a00]=number;
ans[i]=number;
}
else{
a0[++a00]=++num;
ans[i]=num;
}
}else if(u=='1'){
if(a00>=1) {
int number=a0[a00--];
a1[++a11]=number;
ans[i]=number;
}
else{
a1[++a11]=++num;
ans[i]=num;
}
}
}
cout<<num<<endl;
for(int i=1;i<=s;i++){
printf("%d ",ans[i]);
}
printf("\n");
}
return 0;
}