UPC-5627 Boxes(思维)

题目描述
There are N boxes arranged in a circle. The i-th box contains Ai stones.

Determine whether it is possible to remove all the stones from the boxes by repeatedly performing the following operation:

Select one box. Let the box be the i-th box. Then, for each j from 1 through N, remove exactly j stones from the (i+j)-th box. Here, the (N+k)-th box is identified with the k-th box.
Note that the operation cannot be performed if there is a box that does not contain enough number of stones to be removed.

Constraints
1≤N≤105
1≤Ai≤109
输入
The input is given from Standard Input in the following format:

N
A1 A2 … AN
输出
If it is possible to remove all the stones from the boxes, print YES. Otherwise, print NO.
样例输入
5
4 5 1 2 3
样例输出
YES
提示
All the stones can be removed in one operation by selecting the second box.

题意:输入一个序列,这个序列成环形,头尾相接,每次选择序列中一个数作为起点,以顺时针方向依次对每个值做减i操作,i从1到n,保证最后整个序列每个值都被减到0,而不会出现负数的情况。问是否能这样依次减到0,若给出的 序列可以,则输出YES,否则输出NO

我们可以反过来想,对于一个序列,我们选择一个数作为起点依次加i,最后达到给出序列的值的状态。首先,我们要求出层数,也就是我对这个环做了多少轮从1加到N的操作。因为每次都是最序列的值做1加到N的操作,所以我们每轮操作加上的值即等差数列求和公式n*(n+1)/2. 如果数列可以在整数轮次被削减完,那么可能有解,否则一定无解,那么我们对数列求和,除n * (n+1)/2,即做的操作次数,若取模不为零,则一定输出NO。

接下来对于每个数考虑,我们对于一轮增加,两两数之间定有一个断电,如,五个数,对于其中两个相邻的数,必定是,一个加了1,另一个加了5,而这两个相邻的数认为是一个断点。因为两两连续的数之间增值后,必定差值为1,如1和2差值为1,3和4差值为1,而1和5差值为4,这个断点使得某两数差值为n-1,我们计算两两相邻数的差值,若发现小于轮数,那么这两个数之间必有断点,因为断点使差值减了(n-1)否则,差值为1,有t层则差值为t。

对于两数,我们进行多轮操作后,可能有断点,可能是一层一层叠上来的。断点和普通层叠的次数之和为总轮数,那么射、设断点次数为x,普通层叠为y,则x+y=t(总轮数)

再者,我们计算得到的相邻两数差值tmp,tmp=-x*(n-1)+y

这是对于差值的解释,无断点差值+1,有断点差值-n+1

化简后,x=(t-tmp)/n

即计算x断点次数,我们对于每个差值,计算出在此存在的断点次数,求和所有两数之间的断点次数,若正确的话,断点次数和等于轮数,否则断点次数不合理,多了或者少了。

注意要考虑的情况,1 2 3 4 5有解,5 4 3 2 1无解
1 1 1 1 1无解
15 15 15 15 15有解
2 3 4 5 6无解,因为多次轮数是正确的,但基础1 1 1 1 1是有误的,在有误的基础上正确增长也是错误的。

对于两数之差,若大于总层数,必定无解。若求断点数不是整数,必定无解,此处用来解决2 3 4 5 6的情况。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn=100005;
int main()
{
    LL n,a[maxn],b[maxn];
    while(scanf("%lld",&n)!=EOF)
    {
        LL sum=0;
        for(int i=0; i<n; i++)
        {
            scanf("%lld",&a[i]);
            sum+=a[i];
        }
        bool ans=true;
        LL t=sum/(n*(n+1)/2);
        LL tt=t;
        for(int i=0; i<n; i++)
        {
            LL tmp=a[i]-a[(i-1+n)%n];
            if((t-tmp)%n!=0||t<tmp) ans=false;
            else tt-=(t-tmp)/n;
        }
//        printf("%lld    %lld    %lld\n",sum%(n*(n+1)/2),sum,n*(n+1)/2);
        printf("%s\n",ans&&sum%(n*(n+1)/2)==0&&tt==0?"YES":"NO");
    }
}
posted @ 2018-04-20 16:24  KuroNekonano  阅读(100)  评论(0编辑  收藏  举报