[NOIP模拟测试]:折纸(模拟)

强颜欢笑 提交于 2019-11-27 13:39:17

题目描述

小$s$很喜欢折纸。
有一天,他得到了一条很长的纸带,他把它从左向右均匀划分为$N$个单位长度,并且在每份的边界处分别标上数字$0\sim n$。
然后小$s$开始无聊的折纸,每次他都会选择一个数字,把纸带沿这个数字当前所在的位置翻折(假如已经在边界上了那就相当于什么都不做)。
小$s$想知道$M$次翻折之后纸带还有多长。


输入格式

第一行包含两个正整数$N$和$M$,表示纸带的长度和操作的次数。

接下来的一行包含$M$个整数$D_i$,其中$D_i$表示第$i$次选择的数字。


输出格式

输出文件只有一个数字,即纸带最后的长度。


样例

样例输入:

5 2
3 5

样例输出:

2


数据范围与提示

$60\%$的数据中$N\leqslant 3,000,M\leqslant 3,000$。
$100\%$的数据中$N\leqslant {10}^{18},M\leqslant 3,000$。


题解

$60\%$算法:

直接模拟翻折过程,记录每一个点现在的位置即可,每次暴力更新。

记得初始化。

时间复杂度:$\Theta(N\times M)$。

期望得分:$60$分。

实际得分:$60$分。

$100\%$算法:

发现我们并不用关心每个纸带的位置,只用考虑当前操作的位置就好了。

每次翻折之后对所有的操作进行$\Theta(M)$重标号即可,至于式子$D_j=abs(D_i-D_j)$。

时间复杂度:$\Theta(m^2)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
long long n,m;
long long l,r;
long long wzc[5000];
int main()
{
	scanf("%lld%lld",&n,&m);
	l=0,r=n;
	for(int i=1;i<=m;i++)
	{
		scanf("%lld",&wzc[i]);
		for(int j=1;j<i;j++)
			if(wzc[j]>=wzc[i])
				wzc[i]=2LL*wzc[j]-wzc[i];
		r=max(r,2LL*wzc[i]-l);
		l=wzc[i];
	}
	printf("%lld",r-l);
	return 0;
}
 

rp++

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!