zoukankan      html  css  js  c++  java
  • Jzoj4788 序列

    题意:给你a,b两个序列,每次可以在区间[l,r]对每个数加一,求最少的步数使a变成b

    注意,整个过程都是在mod 4的意义下的,a,b所有元素的值都在[0,3]之间

    我们可以先考虑不存在Mod 4 的情况

    我们假设di=max(0,bi-ai)

    那么显然,对于一个位置i,我们需要将其操作max(0,di)次

    考虑从1开始,我们设f[i]表示将1~i的d清零所需要的最小次数

    显然,f[1]=d[1],f[i]=f[i-1]+max(0,d[i]-d[i-1]) (其实这是一个差分的经典应用)

    现在我们来考虑Mod 4 的情况,由于有Mod 4 的影响,我们可以将一系列的d[i]变为d[i]+4k

    这样在一种情况下会减小答案

    若有i<j使得 d[i]-d[i-1]+4<d[j]-d[j-1] 那么,我们就可以将整个[i,j-1]的d都加上4

    这样答案就可以减少(d[i]-d[i-1]-dj+dj-1+4)

    实际上,我们只需要维护d[i]-d[i-1]=-2和-3的个数即可(-1+4=3 0+4=4显然都不可能)

    每次都贪心地去取就可以

    #pragma GCC optimize("O3")
    #pragma G++ optimize("O3")
    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    int n,a[1000010],T;
    int aim(){
    	scanf("%d",&n); int cnt[4]={0},ans=0;
    	for(int i=1;i<=n;++i) scanf("%d",a+i);
    	for(int x,i=1;i<=n;++i){
    		scanf("%d",&x);
    		a[i]=(x-a[i]+4)&3;
    	}
    	for(int i=1;i<=n;++i) ans+=max(0,a[i]-a[i-1]);
    	for(int i=2;i<=n;++i){
    		int j=a[i]-a[i-1];
    		if(j>0){
    			if(cnt[1] && j>1){
    				--cnt[1];
    				++cnt[j];
    				ans-=--j;
    			} else if(cnt[2] && j>2){
    				--cnt[2];
    				++cnt[j];
    				ans-=j-2;
    			}
    		} else ++cnt[j+4];
    	}
    	printf("%d
    ",ans);
    }
    int main(){ for(scanf("%d",&T);T--;aim()); }

  • 相关阅读:
    Linux软件安装
    虚拟地址和物理地址
    python 读写txt文件
    python 浮点数保留几位小数
    Contiki源码结构
    Contiki Rtimer 模块
    Contiki Ctimer模块
    Contiki Etimer 模块
    Contiki Timer & Stimer 模块
    Contiki clock模块
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/9477277.html
Copyright © 2011-2022 走看看