NOIP提高组【JZOJ4788】序列

本文介绍了一种关于数组操作的优化算法,通过定义特定变量并分析不同情况来减少不必要的操作次数,实现对数组中元素的有效调整。算法考虑了各种边界条件,并通过实例展示了如何在O(N)的时间复杂度内解决问题。

Description

这里写图片描述

Data Constraint

这里写图片描述

我们设d[i]表示a[i]要经过多少次操作后才可到达b[i],设c[i]=d[i]-d[i-1]。那么最朴素的想法答案ans=ni=1Max(0,c[i])。但这只是每个数都不会超过自己d[i]的情况,我们还要考虑假设某个数被某个区间包含,后来又多做了4次再次返回自已要求值的情况。显然对于现在的某段区间[i,j],它多做了4次会使c[j]-4,使c[i]+4,那么我们再回想刚才的公式ans=ni=1Max(0,c[i]),我们明显想使ans最小,也就是想使max(0,c[i]+4)+max(0,c[j]-4)

1:当c[j]为1时,显然max(0,c[i]+4)肯定不会比max(c[i],0)+1更小,所以无需考虑。

2:当c[j]为2时,我们发现只有c[i]=-3时才会使答案小1,所以我们看j之前是否有c[i]=-3的数,假设有,就将答案减1,并将c[i]=-3的数量-1,紧接着我们发现c[j]-4后值为-2,所以我们将c[i]=-2的数量+1。

3:当c[j]为3时,我们发现c[i]=-3时会使答案小2,而c[i]=-2时会使答案小1,所以我们看j之前是否有c[i]=-3的数,假设有,就将答案减2,并将c[i]=-3的数量-1。假设没有,我们再看看j之前是否有c[i]=-2的数,假设有,就将答案减1,并将c[i]=-2的数量-1。

4:对于c[j]<0的情况,明显他们对当前答案的贡献为0,所以无需做改变,只需将c[j]=-2的数量或c[j]=-3的数量+1即可。

总时间复杂度为O(N)。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=100005;
int a[maxn],b[maxn],d[maxn],n,i,t,j,k,l,x,y,ans,c[10];
int main(){
//  freopen("data.in","r",stdin);
    scanf("%d",&l);
    while (l){
        scanf("%d",&n);
        for (i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for (i=1;i<=n;i++)
            scanf("%d",&b[i]),d[i]=(b[i]+4-a[i])%4;
        t=0;ans=0;memset(c,0,sizeof(c));
        for (i=n;i>=1;i--)
            d[i]-=d[i-1],ans+=max(0,d[i]);
        for (i=1;i<=n;i++){
            if (d[i]<-1) c[-d[i]]++;
            else if (d[i]>1){
                if (d[i]==2){
                    if (c[3]) c[3]--,ans--,c[2]++;
                }
                else if (d[i]==3){
                    if(c[3]) c[3]--,ans-=2;
                    else if (c[2]) c[2]--,ans--;    
                }
            }
        }
        printf("%d\n",ans);
        l--;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值