题意:
有一长度为n的单调递增序列 。现在这个序列很不稳定,每秒钟都会发生如下变化:如果满足a[i]+1<a[i+1] 那么a[i]++,a[i+1]–。
求最终序列。
由于保证单调递增,所以说,只要有一个位置发生+1的变化,那么这个影响会一直传递到1。直到a[1]=a[2],此时,若在发生变化会使a[2]++。
那么可以发现最后的序列为一个公差为1的等差数列,但是其中允许有一对相同的数字。那么求和 直接模拟即可
最后的a[i]=i-1+(s-n*(n-1)/2)/n+(s-n*(n-1)/2)%n<=i;(将每个元素先变成i-1,此时保证整个序列单调递增,然后求和后在评价分配,最后补齐)
代码略。
序列单调不减:
此时不会产生传递到1的效果,最后的序列中也会有多段相同元素。不能直接O1得到每个答案。
所以需要模拟整个过程,将每个数字-i后,vector维护单调递减的序列,表示一段连续相等的值的最后一个元素的位置。
#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 6;
const int N = 505;
const int inf = 0x3f3f3f3f;
int n;
ll a[maxn];
struct node{
ll x,y;};
vector<node>v;
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),a[i]-=i;
v.pb({
a[1],1});
for(int i=2;i<=n;i++) {
if(a[i]<v.back().x) {
v.pb({
a[i],i});
continue;
}
if(a[i]==v.back().x) continue;
while(v.size()>1&&a[i]-v.back().x>i-v.back().y) {
a[i]-=i-v.back().y;
v.pop_back();
}
if(v.size()==1) {
ll t=(a[i]-v.back().x)/i;
a[i]-=t*(i-1);
v.back().x+=t;
}
if(a[i]==v.back().x) continue;
ll d=a[i]-v.back().x;
node k=v.back();
if(v.size()==1) {
v.back().x++;
} else v.pop_back();
v.pb({
k.x,k.y+d});
}
v.pb({
0,n*10});
int p=0;
for(int i=1;i<=n;i++) {
if(v[p+1].y==i) p++;
printf("%lld ",v[p].x+i);
}
printf("\n");
}