首页 > 其他分享 >大模拟&枚举

大模拟&枚举

时间:2024-08-29 16:15:28浏览次数:9  
标签:int s1 else ++ 枚举 循环 模拟

大模拟

昨天刷了几道普通的大模拟后写了一道整整 \(113\) 行的 \(\text{NOIP}2018\) 提高组,第一天第二题——时间复杂度 累死我了,难度是惊人的绿题(相当于 \(\text{CSP-J}\) 压轴),非常吓人,只需要用到栈,但是状态非常复杂,这就是大模拟题目的令人苦恼之处——耗时间,而且细节很多,稍有不慎就会WA,甚至 \(0\) 分,下面就结合题目本身来讲一下大模拟的解法。

首先,过滤掉无用信息。大模拟类型题目几乎都有着非常长的题面,比如这道题里面,有些东西讲的很少,却极其重要,如本题中的时间复杂度计算方法,都放在了输入格式里面。这里告诉大家输入输出格式里蕴含的信息会占题目的 \(50\%\),必须认真阅读。在读完题后,可以得出以下精简版的题面。

在一个语言中,循环语句的格式为F i x y,结束语句为E,一一对应。如果 \(x ≤ y\) 则进入循环,否则不进入,其中会出现一个整数 \(n\),其大于 \(100\),而 \(x\) 与 \(y\) 如果是数字,小于 \(100\),现在给出你 \(T\) 组数据,每组数据的语句数量以及格式为 O(1) 或者 O(n^w) 的时间复杂度,求是否正确,输出Yes或者No如果循环与结束语句不对应或者变量没有用完的情况下重复使用,输出ERR

其次,考虑怎么去模拟,这一部分无疑是模拟中最难的那一部分。我们可以考虑循环的特点:可以嵌套,那么后进去的先退出,这让你想起了什么?是的,栈啊!那么我们就可以用栈来存储循环语句的信息,一切就水到渠成了。

最后,就只需要写代码,讲几个坑点:

  • 算时间复杂度是不可以直接加的,要用变量找最大值,退出循环后再减回去。
  • 不能开过多的栈,否则栈空间会爆掉。
  • 不能发现错误后直接break,会影响后续输入,应该标记。
#include <bits/stdc++.h>
using namespace std;
char a[1005],b[1005];
string c[105],d[1005];
int f[2000];
int numcmp(string a,string b)
{
	if (a.size() > b.size() || (a.size() == b.size() && a > b)) return 1;
	return 2;
}
int main()
{ 
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t,n;
	cin >> t;
	while (t--)
	{
		memset(f,0,sizeof f);
		int f2 = 1,f3 = 1,sa = 0,sb = 0,o = 0,x = 0,f4 = 1,ma = 0;
		stack<string> s1;
		stack<char> s2;
		char e;
		string k;
		cin >> n >> k;
		if (k[2] == '1') 
		{
			x = 0;
		}
		else 
		{
			x = 0;
			for (int i = 4;i < k.size() - 1;i++)
			{
				x = x * 10 + (k[i] - '0');
			}
		}
		for (int i = 1;i <= n;i++)
		{
			cin >> a[i];
			if (a[i] == 'F') 
			{
				sa++;
				cin >> b[i] >> c[i] >> d[i];
				if (f[b[i]] == 0) 
				{
					s2.push(b[i]);
					f[b[i]]++;
					if (c[i] != "n" && d[i] == "n" && f4)
					{
						o++;
						ma = max(ma,o);
						s1.push("F1");
					}
					else if (c[i] == "n" && d[i] != "n")
					{
						f4 = 0;
						s1.push("F2");
					}				
					else if (numcmp(c[i],d[i]) == 1)
					{
						f4 = 0;
						s1.push("F2");
					}   
					else
					{
						s1.push("F2");
					}
				}
				else  
				{
					f2 = 0;
				}
			}
			if (a[i] == 'E')
			{
				sb++;
				if (!s1.empty()) 
				{	
					if (s1.top() == "F1") o--;
					s1.pop();
					f4 = 1;
					if (!s2.empty())
					{
						char t = s2.top();
						f[t]--;
						s2.pop();
					}
				}
				else 
				{	
					f3 = 0;
				}
			}
		}
		if (f2 == 0 || f3 == 0 || sa != sb) 
		{
			cout << "ERR\n";
		}
		else if (ma == x) 
		{
			cout << "Yes\n";
		}
		else 
		{
			cout << "No\n";
		}
	}
	return 0;
}

枚举

算法简介

枚举,是一种通过找出每一种可能的答案,来求解整个问题的算法。同时可以通过排除一些已经不可能满足要求的情况,减去需要枚举的情况数量,以提升效率。

方法解析

简单枚举,通常使用循环来实现,用伪代码来表示如下。同时,在循环内部,加上一些语句,来判断是否可行,常用的有分支语句。同时,有一些问题可以使用 \(\text{break/continue}\),做优化。这类问题的重点,就是在优化。除了刚刚利用 \(\text{break,continue}\) 优化,可以用根号优化,通常用在判断质数,因数与倍数等等方面,对称性优化。最后就是数学方法。这些题目主要运用代数方法,把本来需要枚举的答案直接求出,效率非常高。这种题目需要很强的思考能力,不容易做对。** 但由于篇幅原因,优化部分将在下篇文章更新**。同时,枚举本身也分为循环枚举、子集枚举与排列枚举(其中子集枚举不讲)。

例题解析

三连击

题意简述

通过组合 \(1\),\(2\),\(......\),\(9\) 组合出三个数,输出所有满足比例为 \(A:B:C\) 的方案,误解输出 No!!!

思路

本题中,如果枚举每一个数位,要循环 \(9^9\) 次,通过很危险。实际上,由于比例确定,我们知道了 \(A\),就可以推导出 \(B\) 和 \(C\),因此只需要枚举一个三位数,即可,只需要枚举 \(987-123=864\) 次,效率极高,再标记判断是否刚好每个数码各出现一次即可。

参考代码

#include <bits/stdc++.h>
using namespace std;
int main()
{
	int a,b,c,s = 0;
	cin >> a >> b >> c;
	for (int x = 1;c * x <= 987;x++)
	{
		int i = x * a,j = x * b,k = x * c,ti = i,tj = j,tk = k,f[15] = {0},fn = 1;
		while (ti != 0) f[ti % 10]++,ti /= 10;
		while (tj != 0) f[tj % 10]++,tj /= 10;
		while (tk != 0) f[tk % 10]++,tk /= 10;
		for (int t = 1;t <= 9;t++) 
		{
			if (f[t] != 1) fn = 0;
		}
		if (fn) cout << i << ' ' << j << ' ' << k << '\n',s++;
	}
	if (s == 0) cout << "No!!!";
	return 0;
}

全排列问题

题意简述

按照字典序输出自然数 \(1\) 到 \(n\) 所有不重复的排列,即 \(n\) 的全排列,要求所产生的任一数字序列中不允许出现重复的数字。

思路

只需要枚举每一位上的数字即可,难点在枚举层数,可以使用一个计数变量,当变量到 \(n\) 时退出循环,返回所谓的上一层。这种思路严格意义上虽然没有使用递归,但用到了回溯思想,也就是 \(\text{DFS}\)。

参考代码

#include <bits/stdc++.h>
using namespace std;
int a[1005];
bool b[1005];
int main() 
{
	int n,m,x = 1,s = 0;
    cin >> n;
    m = n;
	for (int i = 1;i <= m;i++) 
    {
		a[i] = i;
		b[i] = true;
	}
	while (x > 0) 
    {
		s++;
		cout << s << ": ";
		for (int i = 1;i <= m;i++) printf("%5d", a[i]);
		puts('\n');
		x = m;
		while (x > 0) 
        {
			b[a[x]] = 0;
			for (int i = a[x] + 1;i <= n;i ++ ) 
            {
				if (b[i] == false) 
                { 
				    a[x] = i; 
				 	b[i] = true;
				 	break;
				}
			}
			if (i <= n) break;
			x--;
		}
		if (x > 0) 
        {
			int ans = 1;
			for (int i = 1;x + ans <= m && i <= n;i ++) 
            {
				if (b[i] == 0) 
                {
					a[x + ans] = i;
					b[i] = 1;
					ans++;
				}
			}
		}
		
	}
	cout << s;
	return 0;
}

标签:int,s1,else,++,枚举,循环,模拟
From: https://www.cnblogs.com/lzn-tops/p/18386917

相关文章

  • 模拟退火模型 —— 入门案例
    简介模拟退火算法(SimulatedAnnealing,SA)是一种概率型全局优化算法,它受到物理退火过程的启发。在固体材料的退火过程中,材料被加热到一定温度后缓慢冷却,其内部结构逐渐趋于稳定,最终达到能量最低的平衡状态。模拟退火算法正是模仿这一过程,用于寻找数学问题中的全局最优解。特点......
  • 微信开发者工具启用Mock模拟网络请求
    当开发微信小程序在后端接口还没开发好的情况下,想要进行接口调试怎么办?微信开发者工具提供了Mock功能,方便开发者模拟网络请求提前调试。1、在调试器中选Mock2、启用Mock3、新建规则API接口选择request(网络请求)类型参数规则匹配,填写正确的url正则匹配规则(包含参数)模......
  • 使用Hardhat的forking功能在本地模拟EVM链真实环境
    HardhatNetwork可以复制主网区块链状态数据到本地环境,包括所有余额和部署的合约。称为forkingmainnet,可以使得本地测试模拟主网环境,但不用gas,所做的交易也不会真的发生在主网。不止以太坊主网,其他兼容EVM的区块链都可以fork。我们来看一下如何使用这个重要功能。如下例子,是如何......
  • 实践项目-模拟公司自动化运维
    (20240828,准备更新PostgreSQL部分)大纲环境配置系统:Debian12.06环境:阿里云ECS以及虚拟机序号IP地址域名主机名1192.168.100.12k8s-master.yourname.comk8s-master2192.168.100.15k8s-node1.yourname.comk8s-node13192.168.100.16k8s-node2.yourn......
  • 8.28 模拟赛
    比赛复盘浏览所有题后发现所有题都是普及难度。A。数据范围这么小,暴力DP就行。不对\(10^{40}\)的答案……要高精度!!尝试了vector写高精乘发现异常简单。B。一年前我就能不看题解独立切。很快写完了。我清晰地记着分数加分数时分子分母要开__int128。C。又是小\({\Omega......
  • Java--枚举类型
    目录定义声明枚举类EnumMapEnumSet使用场景定义枚举是一个特殊的类,一般表示一组常量,比如一年的4个季节,一年的12月份,方向的东南西北等声明使用enum关键字来定义,各个常量使用逗号,来分割例如:enumColor{RED,GREEN,BLUE}publicclassTest{//执行输出结果publ......
  • 【数据结构】关于二叉搜索树,你知道如何实现增删模拟吗???(超详解)
    前言:......
  • 8.26 模拟赛(NOIP十三连测 #7)
    2024--梦熊&太戈--NOIP十三连测#7【订正】-比赛-梦熊联盟(mna.wang)总结T1基本和CF1245F相同。很快就写完了。T2题意特别难懂,模拟了很长时间后题意还是有些晕,就先放弃了。T3相较于T2看上去简单的多,先冲T3。特殊性质\(A\)有\(50\)分,这可能是正解的关键。尝......
  • 模拟版图设计工程师要学些什么?从入门到入行,你想知道的都在这里了
    IC模拟版图设计是门槛最低的IC设计方向,最低专科学历即可,其他IC设计大多要求本科以上,研究生学历,0基础小白经过几个月的学习也可以入行。那么,待遇还不低的模拟版图设计工程师入行都要学一些什么?下面我们来聊一聊 版图学习最好有一些工艺的基础,了解MOS的基本工作原理,比如PN结......
  • 8.27 模拟赛(2019 CSP-S 真题)
    省流:预计\(40+0+15+0\),实际\(35+4+15+0\)。比赛复盘开局浏览题。A没太看懂(廊桥是什么?机场里有这玩意?);B题很好读懂,但没思路;C括号序列感觉可做;D一眼不会。除C外都感觉没太有戏。顺序开题。看懂A后,分析了一段时间后忘记了题面中“先到先得”的原则,导致推到一些歪的贪心浪......