• luogu P3952 时间复杂度题解


    显然这是一道模拟
    我们要做的就是读入一堆字符串,然后模拟这个循环。
    定义某一层的复杂度为执行完这一层循环之后,消耗的复杂度。
    某层循环的复杂度=(max {)所有并列的下一层循环的复杂度(})。通俗点说,就是在某层循环中有分支的时候,这一层的复杂度=(max {)所有分支的复杂度(}+)本层复杂度。
    最后复杂度=(max {)所有的第一层循环复杂度(})
    考虑到会有分支,所以我们采用递归来实现(当然其本质是栈,但是我不会写)。
    由于要使程序不至于(RE),所以我们要先判断(F)(E)是否匹配。

    一些细节

    1.一定要记得处理完一组数据要初始化所有的东西(虽然不初始化也可以骗到73)
    2.循环中会出现(F i n n)的情况,这种视作(O(1))
    3.在写模拟题之前,请站在出题人的角度想想怎么卡这道题,想全情况之后再写

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<queue>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    const int inf=214748364;
    inline ll read()
    {
    	char ch=getchar();
    	ll x=0;bool f=0;
    	while(ch<'0'||ch>'9')
    	{
    		if(ch=='-') f=1;
    		ch=getchar();
    	}
    	while(ch>='0'&&ch<='9')
    	{
    		x=(x<<3)+(x<<1)+(ch^48);
    		ch=getchar();
    	}
    	return f?-x:x;
    }
    int t,ln,cnt,now,tot;
    char s[101][101],fz[101],bi[101];//s[i]是程序的第i行,fz是它给出的复杂度的字符串,bi[i]表示第i个未被销毁的变量
    bool usd[159],err;//usd记录未被销毁的变量,err记录是否出现ERR
    int ok,fzd;
    void getf()//计算它给的复杂度
    {
    	int len=strlen(fz+1);fzd=0;
    	for(int i=1;i<=len;i++)
    	{
    		if(fz[i]>='0'&&fz[i]<='9')
    			fzd=fzd*10+fz[i]-'0';
    	}
    	if(len==4) fzd=0;
    }
    bool xiaoyu(int k,int len)//判断第二个数是否小于第一个数
    {
    	int c1=0,c2=0,now1=0;
    	for(int i=0;i<len;i++)//计算第一个数
    	{
    		if(s[k][i]>='0'&&s[k][i]<='9')
    		 c1=c1*10+s[k][i]-'0';
    		else if(c1>0)
    		{
    			now1=i;break;
    		} 
    	}
    	if(now1!=0)
    	 for(int i=now1;i<len;i++)//计算第二个数
         {
         	if(s[k][i]>='0'&&s[k][i]<='9')
         	 c2=c2*10+s[k][i]-'0';
    	 }	
    	if(!c2&&(s[k][4]>'9')&&c1) return 1;//处理"n 数字","n n"的情况
    	if(c1>c2&&c2!=0) return 1;
    	return 0; 
    } 
    int work()//计算一个"第一层循环"的复杂度
    {
    	int rtn=0;if(err) return 0;
    	char x=s[now][2];bi[++tot]=x;
    	if(usd[x]) {err=1;printf("ERR
    ");return 0;}//判断是否出现重复变量
    	usd[x]=1;
    	int rst=0,lenn=strlen(s[now]);
    	if(s[now][lenn-1]=='n'&&s[now][4]!='n') rst=1;//处理O(n)+特判"n n"的情况
    	if(xiaoyu(now,lenn)) rst=-inf;//如果不能进入循环,则消除这次答案的影响(进入之后的循环判断ERR)
    	now++;
    	while(s[now][0]!='E')
    	{
    		if(err) return 0;
    		rtn=max(rtn,work());
    		now++;//手动进入程序的下一行(虽然不写也有55pts)
    		if(err) return 0;
    	}
    	if(s[now][0]=='E')
    		usd[bi[tot--]]=0;
    	rtn+=rst;	
    	rtn=max(rtn,0);
    	return rtn;
    }
    int main()
    {
    	t=read();
    	while(t--)
    	{
    		ln=read();scanf("%s",fz+1);cnt=0;now=1;memset(usd,0,sizeof(usd));err=0;//一堆初始化
    		gets(s[0]);
    		for(int i=1;i<=ln;i++)//把字符串全部读入之后手动模拟程序的每一行
    		{
    			gets(s[i]);
    			if(s[i][0]=='F') cnt++;
    			if(s[i][0]=='E') cnt--;
    		}
    		if(cnt)//如果不匹配
    		{printf("ERR
    ");continue;}
    		ok=work();
    		while(now<ln)//可能存在多个"第一层循环"
    		{now++;ok=max(ok,work());}
    		getf();//计算它给出的复杂度
    		if(err) continue;
    		if(ok!=fzd) printf("No
    ");
    		if(ok==fzd) printf("Yes
    "); 
    	}
    }
    
  • 相关阅读:
    bzoj 1087: [SCOI2005]互不侵犯King
    左偏树+菲波那切堆
    bzoj 4455: [Zjoi2016]小星星
    luogu P1941 飞扬的小鸟
    luogu P2814 家谱
    平衡树之非旋Treap
    luogu P3147 [USACO16OPEN]262144
    luogu P1854 花店橱窗布置
    计蒜客NOIP2018模拟1
    [BZOJ3456]城市规划(生成函数+多项式求逆+多项式求ln)
  • 原文地址:https://www.cnblogs.com/lcez56jsy/p/12181186.html
Copyright © 2020-2023  润新知