NOIP模拟 序列 【思维好题】【差分】*

版权声明:欢迎转载,请注明出处,谢谢 https://blog.csdn.net/Dream_maker_yk/article/details/82757323

NOIP模拟 序列


题目:

在这里插入图片描述


思路:

我们考虑先计算出 a i b i a_i到b_i 的最少操作次数
很显然是 ( b i a i + 4 ) % 4 (b_i-a_i+4)\%4
然后我们对这个数列c进行差分
然后就可以发现最后的答案是 i = 1 n m a x ( 0 , c i c i + 1 ) \sum_{i=1}^nmax(0,c_i-c_{i+1})
这个结论比较显然
首先我们知道最后一个位置一定会被操作需要次数次,那么继续考虑
如果位置i比位置i+1要更大,显然这些操作次数是必须要加上的
如果i的操作次数比i+1要小,那么在i+1操作的时候i也可以被一起操作掉。

然后我们考虑怎么优化这个东西
我们考虑对一个区间加上的操作,我们只需要在数组c上面区间加上4,那么我们考虑这样加对差分数组p的实际影响,如果对 [ l , r ] [l,r] 进行操作,那么差分后位置 p l = 4 , p r + = 4 p_l-=4,p_r+=4 ,我们来讨论一下什么情况下答案会更小

当且仅当当前位置是 2 -2 或者 3 -3 ,所以直接对这个进行匹配,记录一下前缀的 2 2 3 3 的个数就好了,然后这题做完了


#include<bits/stdc++.h>
using namespace std;
#define fu(a,b,c) for(int a=b;a<=c;++a)
#define fd(a,b,c) for(int a=b;a>=c;--a)
#define N 100010
#define INF 0x3f3f3f3f
int n,a[N],b[N];
void solve(){
  int cnt2=0,cnt3=0,ans=0;
  scanf("%d",&n);
  fu(i,1,n)scanf("%d",&a[i]);
  fu(i,1,n)scanf("%d",&b[i]);
  fu(i,1,n)a[i]=(b[i]-a[i]+4)%4;
  fu(i,1,n)a[i]-=a[i+1];
  fu(i,1,n)ans+=max(0,a[i]);
  fu(i,1,n){
    switch(a[i]){
      case -2:{
        if(cnt3)cnt3--,cnt2++,ans--;
        break;        
      }
      case -3:{
        if(cnt3)cnt3--,ans-=2;
        else if(cnt2)cnt2--,ans--;
        break;        
      }
      case 2:{cnt2++;break;}
      case 3:{cnt3++;break;}
    }
  }
  printf("%d\n",ans);
}
int main(){
  int T;scanf("%d",&T);
  while(T--)solve();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/Dream_maker_yk/article/details/82757323