Codeforces Round 983 (Div. 2) E.Balanced思路整理与题解

5 阅读3分钟

 题目链接:codeforces.com/contest/203…

+1 +2 +1,就是中间的数变大,两边的数变小,对一系列数进行一个这样的操作:

......不动 不动 不动 操作 不动 操作 不动 操作 不动 操作 不动 不动 不动.........

就可以实现:将一些列数中,中间的数+2,首尾的数+1,+2的数用红色表示,+1的数用蓝色表示,以上操作后的结果:
......不动 不动 不动 操作 不动 操作 不动 操作 不动 操作 不动 不动 不动.........

这样利用+2和+1的差异,可以对一个区间两端点的数的差进行修改,这是最关键的需要意识到的地方,还有一个关键点如下,我们引入负操作

对一列数中,除第i个数外,所有的数进行操作,如果关注这些数之间的相对大小,那么相当于对第i个数-2,对第i个数两边的数分别-1。负操作和正操作可以互相抵消,因为一次负操作是:
-1 -2 -1而正操作是 1 2 1,所以可以抵消。

之后使用常用方法思考:

对于n=1 ,已经balanced

对于n=3, a1 a2 a3,三个数,可以先针对两端点,达到 a1=a3,对a1进行操作,操作数为a3-a1(可正可负)。

然后再对a2进行操作,使a1=a2=a3。

类似的,对于a1.....an,n个数,

先达到端点相等

i from 1 to n/2,依次让a[i]=a[n-i+1]:

令d=a[n-i+1]-a[i]

区间从位置i开始,向左,直到1,每隔2个数进行d次操作。(d可正可负)

从位置n-i+2开始,向右,直到n,每隔两个数进行d次操作。

尤其注意:对a1修改后,a2也跟着修改了,a2的变动会影响a2和a[n-1]达到相等的过程。

再从小区间相等达到大区间相等

现在有了,a1=an a2=a[n-1] ...,再从中间往两边,每次修改靠中间的两个对称位置上的数,使这两个数和他们中间所夹的数相等。

#include<iostream>
#include<cstdio>
#include<climits>
#include<cstring>

using namespace std;

#define ll long long
#define endl "\n"

const int maxn=2*1e5+20;
ll D[2][maxn],ans[maxn];
ll a[maxn];
int n;

inline int nxt(int x) {return x==n? 1:x+1 ;}
inline int lst(int x) {return x==1? n:x-1 ;}
int main()
{
    //freopen("D:\in.txt","r",stdin);
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int t;
    cin>>t;
    while(t--)
    {

        cin>>n;
        for(int i=0;i<=n;i++) D[0][i]=D[1][i]=0;
        for(int i=1;i<=n;i++) cin>>a[i];

        //! a[i] must be updated
        ll delta=0;
        for(int i=1;i<=n/2;i++)
        {
            int l=i,r=n-i+1;
            ll d=a[r]-(a[l]+delta);
            delta=d;
            D[i%2][1]+=d;
            D[i%2][i+1]-=d;
            D[(i%2)^1][n+2-i]+=d;
            D[(i%2)^1][n+1]-=d;
        }
        for(int i=1;i<=n;i++)
        {
            D[0][i]+=D[0][i-1];
            D[1][i]+=D[1][i-1];
            ans[i]=D[i%2][i];
            a[i]+=ans[i]*2;
            a[lst(i)]+=ans[i];
            a[nxt(i)]+=ans[i];
        }

        for(int i=0;i<=n;i++) D[0][i]=D[1][i]=0;
        for(int i=n/2;i>=1;i--)
        {
            ll d=a[i]-a[i+1];
            D[(i+1)%2][i+1]+=d;
            D[(i+1)%2][n-i+1]-=d;
            a[i]+=d;
        }

        for(int i=1;i<=n;i++)
        {
            D[0][i]+=D[0][i-1];
            D[1][i]+=D[1][i-1];
            ans[i]+=D[i%2][i];
        }
        ll minn=LLONG_MAX;
        for(int i=1;i<=n;i++) minn=min(minn,ans[i]);
        for(int i=1;i<=n;i++) ans[i]-=minn;
        for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
        cout<<endl;
    }
    return 0;
}