• 【洛谷5698】[CTSC1998] 算法复杂度(又是被模拟吊打的一天)


    点此看题面

    • 给定一个程序,包含下列语句:

      • begin:开始程序。
      • loop x:开始一个(x)次的循环,其中(x)为正整数或(n)
      • op x:执行(x)个单位的操作,其中(x)为正整数或(n)
      • break:直接退出循环。
      • continue:跳过这次循环的剩余语句,直接进入下一次循环。
      • end:结束程序/循环。
    • 求一个多项式(不能忽略常数项和系数),表示最终复杂度。

    • 循环层数(le20),最终系数(le10^9)

    此题数据出锅

    尽管题目中保证了(x)为正整数或(n),然而数据中依然出现了(x=0)的情况。。。

    为了通过此题,必须特判一下,如果loop x操作中(x=0),将其视作(x=n)

    纯粹模拟

    显然这种东西是要对每层循环开栈进行模拟的,对此考虑开一堆奇奇怪怪的数组:

    • (S[x],P[x]):分别表示进入第(x)层循环所有系数之积以及(n)的次数
    • (G[x]):表示第(x)层循环的循环次数x(可以用(G[x]=0)表示(n))。
    • (C[x][y]):记录第(x)层循环(y)次项的系数。

    然后对于每种操作分类讨论:

    • loop:进入一个新的循环,求出(G[T]),然后据此在(S[T-1])(P[T-1])的基础上进行修正。
    • op:如果(x=n),给(C[T][P[T]+1])加上(S[T]);否则给(C[T][P[T]])加上(S[T] imes x)
    • break:相当于这个循环只执行了一次,所以消去(G[T])的贡献,然后忽视这个循环之后的语句(忽视可以用(S[T]=0)标记)。
    • continue:只要忽视这个循环之后的语句就好了。
    • end:把这个循环的贡献加到前一个循环中。

    口胡起来就是这样,具体实现还是有一些细节的,详见代码。。。

    代码:(O(20|s|))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 30
    #define LL long long
    using namespace std;
    int n,P[N+5];LL ans[N+5],G[N+5],S[N+5],C[N+5][N+5];string s; 
    int main()
    {
    	RI T=0,i;LL x;ios::sync_with_stdio(false),cin>>s,S[0]=1,P[0]=0;W(~T)
    	{
    		if(cin>>s,s=="loop")//循环
    		{
    			if(++T,S[T]=S[T-1],P[T]=P[T-1],cin>>s,s=="0"||s=="n") {G[T]=0,++P[T];continue;}//如果x=n(因数据出锅有x=0)
    			for(x=i=0;i^s.length();++i) x=x*10+(s[i]&15);G[T]=x,S[T]*=x;continue;//如果x为正整数
    		}
    		if(s=="op")//操作
    		{
    			if(cin>>s,!S[T]) continue;if(s=="n") {C[T][P[T]+1]+=S[T];continue;}//如果x=n
    			for(x=i=0;i^s.length();++i) x=x*10+(s[i]&15);C[T][P[T]]+=S[T]*x;continue;//如果x为正整数
    		}
    		if(s=="break")//退出循环
    		{
    			if(!T||!S[T]) continue;if(!G[T]) for(i=0;i<=N;++i) C[T][i]=C[T][i+1];//如果G[T]=n
    			else for(i=0;i<=N;++i) C[T][i]/=G[T];S[T]=0;continue;//如果G[T]为正整数
    		}
    		if(s=="continue") {T&&(S[T]=0);continue;}//跳过循环,直接忽视后面语句
    		if(s=="end") {for(i=0;i<=N;++i) (T?C[T-1]:ans)[i]+=C[T][i],C[T][i]=0;--T;continue;}//结束循环,把贡献归到上一层循环
    	}
    	for(x=0,i=N;~i;--i) ans[i]&&(x?(cout<<'+',0):(x=1),//输出答案
    		(!i||ans[i]^1)&&(cout<<ans[i],0),i&&(cout<<'n',i^1&&(cout<<'^'<<i,0)));//注意一些判断
    	return !x&&(cout<<'0'<<endl),0;
    }
    
  • 相关阅读:
    转载高效的MySQL分页 枫
    [笔记]NFC笔记——WUP_REQ 和 WUP_RES 消息结构
    [笔记]NFC笔记——PSL_REQ 和 PSL_RES 消息结构
    [笔记]C语言中二级指针简单例子
    [笔记]NFC协议规范学习笔记汇总
    [笔记]C语言中预定义符 __FILE__, __LINE__, __FUNCTION__, __DATE__, __TIME__ 的使用演示
    [笔记]如何限制用户在5分钟之后才能重复同样操作
    [笔记]NFC笔记——ATR_RES 消息结构
    简单的具备自动检测行为的文本框控件
    多重AutoComplete的Textbox
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu5698.html
Copyright © 2020-2023  润新知