折纸带
【问题描述】
一张长度为?的纸带,我们可以从左至右编号为0 −?(纸带最左端标号为
0) 。现在有?次操作,每次将纸带沿着某个位置进行折叠,问所有操作之后纸带
的长度是多少。
【输入格式】
第一行两个数字?,?如题意所述。
接下来一行?个整数代表每次折叠的位置。
【输出格式】
一行一个整数代表答案。
【样例输入】
5 2
3 5
【样例输出】
2
【样例解释】
树上有只鸟。
【数据规模与约定】
60%的数据,?,? ≤ 3000。
对于100%的数据,? ≤ 10 18 ,? ≤ 3000。
思路:
这个题首先考虑的是并查集
用一个f数组来记录每个点每次折叠后所处的相应位置
但是,一共有10^18个点
所以用并查集的做法只有60分
现在考虑优化
在用并查集的过程中
我们不难发现每次折叠都更新的全部的点中
只有接下来会用来作为折痕的点是有用的
所以我们可以把f数组优化成大小为3000只用来记录折痕当前位置的数组
然后每次折叠维护一次
最后输出答案
来,上代码:
#include<cstdio> #include<iostream> #include<algorithm> using namespace std; unsigned long long int n,m,a[3001],len; int main() { cin>>n>>m;//用scanf会崩溃所以用cin或者读入优化,这里用cin len=n; for(int i=1;i<=m;i++) cin>>a[i]; for(int i=1;i<=m;i++) { unsigned long long int mid=a[i]; if(len-mid>mid) { for(int j=1+i;j<=m;j++) { if(a[j]>mid) a[j]-=mid; else a[j]=mid-a[j]; } } else { for(int j=1+i;j<=m;j++) { if(a[j]>mid) a[j]=mid-a[j]+mid; } } len=max(len-mid,mid); } cout<<len<<endl; return 0; }