折纸带

【问题描述】


一张长度为?的纸带,我们可以从左至右编号为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;
}

 

posted @ 2016-11-08 08:50  IIIIIIIIIU  阅读(334)  评论(0编辑  收藏  举报