Luogu P3952时间复杂度

一个错误的代码

  • 没有用栈 : 之前的循环如果没有执行,down = 0,会对后面产生影响,down实际上不需要

写了将近两个小时。。。郁闷

#include<cstdio>
#include<algorithm>
#include<locale>
#include<cstring>
#include<queue>
#define N 1000001
using namespace std;
int stk[110],u[30],top;
int L,t;
int output[110];
int main()
{
	freopen("in.txt","r",stdin);
	scanf("%d",&t);
	for(int k = 1;k <= t;++k)
	{
		char cmd[11];
		int cnt = 0,ans,down = 1,complex = 0,maxc = -1;
		memset(u,0,sizeof(u));
		scanf("%d",&L);
		scanf("%s",cmd);
		if(cmd[2] == '1')
		{
			ans = 0;
		}
		else
		{
			int i = 4;
			ans = 0;
			while(isdigit(cmd[i]))
			{
				ans = ans*10 + cmd[i++] - 48;
			}
		}
		getchar();
		for(int i = 1; i <= L; ++i)
		{
			gets(cmd);
			int x = 0,y = 0;
			if(cmd[0] == 'F' && down == 1)
			{
				++cnt;
				int tx = 4,ty = 6;
				if(isdigit(cmd[4]))
				{
					while(cmd[tx] != ' ')
					{
						x = x*10 + cmd[tx++] - 48;
					}
				}
				else{
					tx = 5;
					x = N;
				}
				if(isdigit(cmd[tx + 1]))
				{
					ty = tx + 1;
					while(cmd[ty] != ' ')
					{
						y = y*10 + cmd[ty++] - 48;
					}
				}
				else
				{
					y = N;
				}			
				
				
				if(x == N){
					down = 0;
				}
				else
				{
					if(y == N)
					{
						if(u[cmd[2] - 'a' + 1] == 0){
							u[cmd[2] - 'a' + 1] = 1;
							stk[++top] = cmd[2] - 'a' + 1;
							complex++;
						}
						else
						{
							printf("Conflict
");
							down = 0;
							output[k] = -1;
						}
					}
					else
					{
						if(x >= y) down = 0;
						else if(x < y)
						{
							if(u[cmd[2] - 'a' + 1] == 0)
							{
								u[cmd[2] - 'a' + 1] = 1;
								stk[++top] = cmd[2] - 'a' + 1;
								complex++;
							}
							else
							{
								printf("Conflict
");
								down = 0;
								output[k] = -1;
							}
						}
					}
				}
			}
			else if(cmd[0] == 'E')
			{
				--cnt;
				if(down == 1)
				{
					u[stk[top--]] = 0;
					maxc = max(maxc,complex);
					complex = 0;
				}
				//printf("cnt--,%d
",cnt);
			}
			else if(down == 0)
			{
				++cnt;
				maxc = max(maxc,complex);
				if(maxc == ans)
				{
					output[k] = 1;
				}
				else
				{
					output[k] = 0;
				}
			}			
		}
		maxc = max(maxc,complex);
		if(maxc == ans)
		{
			output[k] = 1;
		}
		else
		{
			output[k] = 0;
		}
		if(cnt != 0) output[k] = -1,printf("cnt != 0 %d  
",cnt);
	}
	for(int i = 1;i <= t;++i)
	{
		if(output[i] == 1) printf("Yes
");
		else if(output[i] == -1) printf("ERR
");
		else printf("No
");
	}
	return 0;
}

脑子呢?

决定放弃,参考Luogu上的题解(离线做法),要用栈!!!
#include<cstdio>
#include<stack>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;

const int maxl=105;

int t,l,w;
string o;
string code[maxl];
//一个函数来获取代码中的正整数
//用于获得c串下标为x的中的正整数,我们将 F x 1 n 中的n也看作整数,有利于后续对循环的处理。
//n也就是特判一下,其余的模拟快读就好了
int sread(int &x,string c)
{
	int res=0;
	int len=c.size();
	while(c[x]<'0' || c[x]>'9'&&x<c.size())
	{
		if(c[x]=='n')
		{
			++x;
			return 1000000;
		}
		++x;
	}
	while(c[x]>='0' && c[x]<='9')
	{
		res*=10;
		res+=c[x]-'0';
		++x;
	}
	return res;
}
//写一个函数以获取复杂度:
int geto()
{
	int res=0,x=3;
	int len=o.size();
	if(o[2]=='n') res=sread(x,o);
	else res=0;
	return res;
}

然后开始模拟循环,同时判断语法是否有误,并计算复杂度。我们写一个int check()函数,结果用res保存,若返回值为-1,则代表有语法错误,否则代表代码复杂度。(当前复杂度用now保存)。

首先考虑没有语法错误的情况:

我们在模拟的时候,肯定需要一个栈s。
遍历一遍代码:

  • 如果遇到了F,那么获取变量名,用k保存,获取 F x i j 中的 i j,分别用 a b 保存。将 k 进栈。
  • 如果 b<a ,那么没有进入循环。用一个 flag 来保存最早的没有没有进入的 k。如果都进入了,则flag为-1。
  • 如果 a<=b ,代表进入循环,此时若 b-a>1000 并且 flag 为 -1 ,则本层循环对复杂度有贡献,执行 now++ 操作。同时我们用 ef[26] 保存 now++ 时 k 的信息(ef[k]=true)。(在k出栈时now - -,ef[k]=false)并更新res。(res=max(res,now))

如果遇到了E,那么同样获取变量名 k ,将k弹出(因为没有语法错误,栈一定不空)。同时判断 flag是否为 k ,若为 k ,则 flag=-1 代表已经出了没有贡献的循环。在判断k是否对复杂度有贡献,若有,则now-,ef[k]=false;

最后return res;

再来在此基础上考虑有语法错误的情况:
  • F 和 E 不匹配 (类似于括号匹配):
    ① F比E多,只需在k出栈时判断栈是否为空,若为空则有语法错误,直接return -1。
    ② F比E少,只需在遍历完代码后判断栈是否不为空,若不空则有语法错误,直接return -1。
  • 新建的变量与已经存在但未被销毁的变量重复:
    用一个bool数组 ins[26] 表示当前,哪些变量被用过。那么只需在原来的基础上:
    ① 在k入栈时,判断k是否已经被用过(即k是否在栈中),若用过则有语法错误,直接return -1。
    ② 在k出栈时,判断栈是否为空,若为空则有语法错误,直接return -1。
    分析到此结束。
int check()
{
	int res=0,now=0;
	int a,b,x;
	stack<int> s;
	int flag=-1;
	bool ins[26]= {0};
	bool ef[26]= {0};
	for(int i=1; i<=l; i++)
	{
		if(code[i][0]=='F')
		{
			int k=code[i][2]-'a';
			if(ins[k]) return -1;
			s.push(k);
			ins[k]=true;
			x=4;
			a=sread(x,code[i]);
			b=sread(x,code[i]);
			//printf("a:%d  b:%d
",a,b);
			if(b-a>1000)
			{
				if(flag==-1)
				{
					now++;
					res=max(res,now);
					ef[k]=true;
				}
			}
			if(a>b)
			{
				if(flag==-1) flag=k;
			}
		}
		if(code[i][0]=='E')
		{
			if(s.empty()) return -1;
			int k=s.top();
			s.pop();
			ins[k]=false;
			if(flag==k) flag=-1;
			if(ef[k])
			{
				ef[k]=false;
				now--;
			}
		}
	}
	if(s.size()) return -1;
	return res;
}

int main()
{
	scanf("%d",&t);
	while(t--)
	{
		int ww;
		scanf("%d ",&l); //选用getline(cin,s)读入一整行代码;
		getline(cin,o);    //注意%d后的空格(输入中l后有一个空格)
		w=geto();
		for(int i=1; i<=l; i++) getline(cin,code[i]);
		ww=check();
		if(ww==-1) puts("ERR");
		else
		{
			if(ww==w) puts("Yes");
			else puts("No");
		}
	}
}
岂能尽如人意,但求无愧我心
原文地址:https://www.cnblogs.com/Zforw/p/10800224.html