jzoj4788-[NOIP2016提高A组模拟9.17]序列【差分,贪心】

    xiaoxiao2023-10-19  158

    正题


    题目大意

    一个序列 A A A可以每次选择一段区间 ( A i + 1 ) % 4 ( i ∈ [ l . . r ] ) (A_{i}+1)\%4(i\in [l..r]) (Ai+1)%4(i[l..r])。求最少次数使其变成 B B B序列。


    解题思路

    先计算出每个数字最少加多少可以变成目标数字记录入 a a a数组。

    然后若不考虑一个数要取模多次的话答案就是 ∑ i = 1 n max ⁡ { a i − a i − 1 , 0 } ( a 0 = 0 ) \sum_{i=1}^n \max\{a_i-a_{i-1},0\}(a_{0}=0) i=1nmax{aiai1,0}(a0=0)

    但是这道题变成了每个柱子的高度是 4 k i + a i ( k ∈ N ) 4k_{i}+a_{i}(k\in \mathbb{N}) 4ki+ai(kN) 那么我们考虑若一段区间 [ l . . r ] [l..r] [l..r] k k k要加1会更优那么有 a l − a l − 1 + 4 < a r + 1 − a r a_{l}-a_{l-1}+4<a_{r+1}-a_{r} alal1+4<ar+1ar 那么答案就可以减去 ( a r + 1 − a r ) − ( a l − a l − 1 + 4 ) (a_{r+1}-a_{r})-(a_{l}-a_{l-1}+4) (ar+1ar)(alal1+4) 那么我们枚举 r r r,开个桶来计算 l l l


    c o d e code code

    #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int N=101000; int T,n,a[N],ans=2147483647,t[5]; int main() { scanf("%d",&T); while(T--) { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); memset(t,0,sizeof(t)); ans=0; for(int i=1;i<=n;i++){ int val; scanf("%d",&val); a[i]=(val-a[i]+4)%4; ans+=max(a[i]-a[i-1],0); } for(int i=2;i<=n;i++){ int c=a[i]-a[i-1]; if(c>0){ if(t[1]&&c>1) t[1]--,t[c]++,ans-=c-1; else if(t[2]&&c>2) t[2]--,t[c]++,ans-=c-2; } else t[c+4]++; } printf("%d\n",ans); } }
    最新回复(0)