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");
}
}