jzoj4788 序列

来源:互联网 发布:复活吧我的勇士java 编辑:程序博客网 时间:2024/05/17 02:52

题目

给定序列A,B,每一次操作可以让A的i~j这个区间内+1%4,求多少次操作才能让A达到B

先求出对于第i个位置从Ai>Bi要做多少次,记作Di
如果不考虑模的话,这题就是一个经典的粉刷问题,
Ans=DiDi1|(Di>Di1)
然后我们再考虑模,如果操作次数+4对正确性没有影响,那么我们什么时候才需要让某个地方再做4次以达到答案减小的目的呢,不难发现就是这种情况。
这里写图片描述
如果这样的话我们的代价其实就是 左右两边的和 减去 中间的 (假设中间的是相同高度)

我们可以让中间全部加4,以此达到可以一次做完 那么这样答案就是左边的高度加上中间加四后高出来的高度

我们可以算出,在左边我们需要增加了多少次,在右边减去了多少,然后统计一下需要增加X次的个数(统计相邻的),这样我们每次找到一个最不亏的(亏的话干脆不加),就把答案加上增加的次数再减去少掉的次数就可以了。

CODE

#include <cstdio>#include <iostream>#include <cstring>#define N 100010using namespace std;int a[N],b[N],n,t,ans,d[100];int main() {    cin>>t;    for (int iii=0; iii<t; iii++) {        memset(d,0,sizeof d);        cin>>n;        for (int i=1; i<=n; i++) {            scanf("%d",&a[i]);        }        for (int i=1; i<=n; i++) {            scanf("%d",&b[i]);            a[i]=(b[i]-a[i]+4)%4;        }        ans=a[1];        for (int i=1; i<n; i++) {            if (a[i]<a[i+1]) {                ans+=a[i+1]-a[i];                for (int j=1; j<a[i+1]-a[i]; j++) {                    if (d[j]) {                        ans-=(a[i+1]-a[i]-j);                        d[j]--;                        d[a[i+1]-a[i]]++;                        break;                    }                }            } else {                d[a[i+1]+4-a[i]]++;            }        }        printf("%d\n",ans);    }}
0 0
原创粉丝点击