[CSP-S模拟测试]:简单的填数(贪心+模拟)

题目描述

对于一个长度为$n$,且下标从$1$开始编号的序列$a$,我们定义它是「合法的」,当且仅当它满足以下条件:
·$a_1=1$
·对于$i\in [1,n),a_i\leqslant a_{i+1}\leqslant a_i+1$且$a_{i+1}$为正整数
·对于任意在$a$中出现过的数$v$,记它的出现次数为$s$,则$2\leqslant s\leqslant 5$
给定一个长度为$n$的序列$a$,其中有一些位置为$0$,你需要在这些位置上任意填数,使得$a$成为一个合法的序列,并且最大化$a_n$的值。


输入格式

第一行一个数$n$,表示序列的长度。
第二行$n$个整数,第$i$个整数表示$a_i$,如果$a_i=0$,则表示这个位置没有填数。


输出格式

如果不存在合法的填数方案,则输出$−1$;否则第一行输出一个整数,表示最大的$a_n$;第二行$n$个正整数,第$i$个数表示完成填数后的序列的第$i$个元素。 如果有多组合法的解,输出任意一组


样例

样例输入1:

7
0 1 0 0 0 3 0

样例输出1:

3
1 1 2 2 3 3 3

样例输入2:

4
0 0 0 3

样例输出2:

-1


数据范围与提示

对于$30\%$的数据,$n\leqslant 1,000$;
对于另外$30\%$的数据,数据保证随机生成;
对于$100\%$的数据,$2\leqslant n\leqslant 2\times {10}^5,0\leqslant a_i\leqslant {10}^5$。


题解

对于每个位置维护两个二元组,分别是$up(x,l)$表示当前位置能填的最大值$x$和连续个数$l$;$down(x,l)$表示当前为只能填数的最小值$x$和连续个数$l$。

求$up$就是尽可能的往上升,求$down$反之。

第一问就是最后一位的最大值,至于第二问倒着扫一边即可求出。

时间复杂度:$\Theta(n)$。

期望的分:$100$分。

实际的分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
int n;
int a[200001];
pair<int,int> up[200001],down[200001];
int sum[100001],ans[200001];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	if(a[1]>1){puts("-1");return 0;}
	a[1]=1;
	up[1]=down[1]=make_pair(1,1);
	for(int i=2;i<=n;i++)
	{
		up[i]=make_pair(up[i-1].first,up[i-1].second+1);
		down[i]=make_pair(down[i-1].first,down[i-1].second+1);
		if(up[i].second>2)
		{
			up[i].first++;
			up[i].second=1;
		}
		if(down[i].second>5)
		{
			down[i].first++;
			down[i].second=1;
		}
		if(a[i])
		{
			if(up[i].first==a[i])up[i].second=min(up[i].second,2);
			if(up[i].first>a[i])up[i]=make_pair(a[i],2);
			if(down[i].first<a[i])down[i]=make_pair(a[i],1);
			if(up[i].first<a[i]||down[i].first>a[i]){puts("-1");return 0;}
		}
	}
	if(up[n].second==1)up[n]=make_pair(up[n-1].first,up[n-1].second+1);
	printf("%d\n",up[n].first);
	ans[n]=up[n].first;
	sum[a[n]]=1;
	for(int i=n-1;i;i--)
	{
		if(a[i])ans[i]=a[i];
		else
		{
			int flag=min(ans[i+1],up[i].first);
			if(sum[flag]==5)flag--;
			ans[i]=flag;
		}
		sum[ans[i]]++;
	}
	for(int i=1;i<=n;i++)printf("%d ",ans[i]);
	return 0;
}


rp++

原文地址:https://www.cnblogs.com/wzc521/p/11495887.html

时间: 2024-10-02 03:08:02

[CSP-S模拟测试]:简单的填数(贪心+模拟)的相关文章

[CSP-S模拟测试]:简单的括号序列(组合数)

题目传送门(内部题82) 输入格式 一行一个字符串$ss$,保证$ss$中只包含$'('$和$')'$. 输出格式 一行一个整数,表示满足要求的子序列数对$10^9+7$的结果. 样例 样例输入1: )(()() 样例输出1: 6 样例输入2: ()()() 样例输出2: 7 样例输入3: ))) 样例输出3: 0 数据范围与提示 样例解释: 第一组样例中,有以下几种子序列满足条件(字符串下标从$1$计数): 删除$1,5$位置的字符,得到$(())$ 删除$1,2,3,4$位置的字符,得到$(

蛇形填数(模拟)

#include<cstdio> #include<cstring> using namespace std; int a[10][10]; int main() { int n,x,y,tot; scanf("%d",&n); memset(a,0,sizeof(a)); a[x=1][y=n]=1;tot=1; while(tot<n*n) { while(x+1<=n&&a[x+1][y]==0) a[++x][y]=+

[CSP-S模拟测试]:简单的期望(DP)

题目描述 从前有个变量$x$,它的初始值已给出. 你会依次执行$n$次操作,每次操作有$p\%$的概率令$x=x\times 2$,$(100−p)\%$的概率令$x=x+1$. 假设最后得到的值为$w$,令$d$为$w$的质因数分解中$2$的次数,求$d$的期望. 输入格式 从文件$exp.in$中读入数据. 第一行三个整数$x,n,p$,含义见题目描述. 输出格式 输出到文件$exp.out$中. 一行一个实数,表示$d$的期望. 如果你的答案与标准答案的误差不超过$10^{−6}$,则判定

[CSP-S模拟测试]:简单的操作(二分图+图的直径)

题目描述 从前有个包含$n$个点,$m$条边,无自环和重边的无向图. 对于两个没有直接连边的点$u,v$,你可以将它们合并.具体来说,你可以删除$u,v$及所有以它们作为端点的边,然后加入一个新点$x$,将它与所有在原图中与u或v有直接连边的点连边. 你需要判断是否能通过若干次合并操作使得原图成为一条链,如果能,你还需要求出这条链的最大长度. 输入格式 从文件$merge.in$中读入数据. 第一行两个正整数$n,m$,表示图的点数和边数. 接下来m行,每行两个正整数$u,v$,表示$u$和$v

[CSP-S模拟测试]:小L的数(数位DP+模拟)

题目传送门(内部题132) 输入格式 第一行一个整数$t$. 接下来$t$行每行一个整数$n$. 输出格式 $t$行,每行一个整数表示答案. 样例 样例输入: 418182312326910521093203 样例输出: 1233 数据范围与提示 对于前$5\%$的测试数据,满足答案小于等于$1$. 对于前$20\%$的测试数据,满足答案小于等于$2$. 对于前$40\%$的测试数据,满足$n\leqslant 300,000$. 对于前$60\%$的测试数据,满足答案小于等于$3$,$n\le

[CSP-S模拟测试]:简单的区间(分治)

题目描述 给定一个长度为$n$的序列$a$以及常数$k$,序列从$1$开始编号.记$$f(l,t)=\sum \limits_{i=l}^ra_i-\max \limits_{i=l}^r\{a_i\}$$求合法的正整数对$(l,r)$的数量,满足$1\leqslant l<r\leqslant n$,且$k|f(l,r)$. 输入格式 第一行两个正整数$n$和$k$. 第二行包含$n$个正整数,第$i$个正整数表示$a_i$. 输出格式 一行一个正整数,表示答案. 样例 样例输入1: 4 3

[CSP-S模拟测试]:简单的玄学(数学)

题目描述 有$m$个在$[0,2^n)$内均匀随机取值的整型变量,球至少有两个变量取值相同的概率.为了避免精度误差,假设你的答案可以表示成$\frac{a}{b}$的形式,(其中$(a,b)=1$),你需要输出$a$和$b$对${10}^6+3$取模后的值. 输入格式 第一行两个正整数$n,m$. 输出格式 一行两个整数,它们的含义如题所述. 样例 样例输入1: 3 2 样例输出1: 1 8 样例输入2: 1 3 样例输出2: 1 1 样例输入3: 4 3 样例输出3: 23 128 数据范围与

[CSP-S模拟测试]:kill(二分答案+贪心)

题目传送门(内部题50) 输入格式 第一行包含四个整数$n,m,s$,表示人数.怪物数及任务交付点的位置.第二行包含$n$个整数$p_1,p_2,...,p_n$.第三行包含$n$个整数$q_1,q_2,...,q_n$. 输出格式 输出一行包含一个整数$ans$,表示答案. 样例 样例输入: 2 4 52 106 1 4 8 样例输出: 5 数据范围与提示 样例解释: 第一个人打位置为$4$的怪物,第二个人打位置为$8$的怪物,前者花$3$的时间,后者花$5$的时间,该方案对应的时间为$5$,

Android单元测试与模拟测试详解

测试与基本规范 为什么需要测试? 为了稳定性,能够明确的了解是否正确的完成开发. 更加易于维护,能够在修改代码后保证功能不被破坏. 集成一些工具,规范开发规范,使得代码更加稳定( 如通过 phabricator differential 发diff时提交需要执行的单元测试,在开发流程上就可以保证远端代码的稳定性). 2. 测什么? 一般单元测试: 列出想要测试覆盖的异常情况,进行验证. 性能测试. 模拟测试: 根据需求,测试用户真正在使用过程中,界面的反馈与显示以及一些依赖系统架构的组件的应用测