codeforces 1392 F Omkar and Landslide

link

题意:

有一长度为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");
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值