1. 程式人生 > >AtCoder Regular Contest 085 F NRE 線段樹優化dp

AtCoder Regular Contest 085 F NRE 線段樹優化dp

題意

有長度為n初始全為0的陣列A和僅由0和1組成的陣列B。現在給出m個區間,每次可以選擇某個區間[l,r],使得A陣列下標在[l,r]之間的元素變為1。問A和B最小不同位置數量是多少。
n,m<=200000

分析

比賽的時候看成是區間取反,就以為這是道不可做題。
這題的題解用了比較巧妙的轉化方式。把(ai,bi)看成是一個數對,那麼答案其實就是(1,0)和(0,1)的數量,也就相當於(0,1)+(@,0)-(0,0)的最小值,其中@表示可以取任意值。注意到(@,0)的數量是固定的,那麼要求的實際就是(0,1)-(0,0)的最小值,也就是說,1的沒有貢獻的。
然後就可以大力dp了。
設f[i,j]表示前i個數已經確定,且當前的最後一個1在位置j時的最小代價。
我們可以列舉以i為起點的區間,設為[i,r]
那麼有f[i,r]=min(f[i-1,k]+w[k+1,i-1])。其中若l>r則w[l,r]=0,反之則w[l,r]為b[l,r]中1的數量-0的數量。
用線段樹優化即可。

程式碼

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

const int N=200005;
const int inf=1000000000;

int n,m,s1[N],s0[N];
struct tree{int mn,tag;}t[N*5];
vector<int> vec[N];
pair<int
,int> a[N]; int read() { int x=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void pushdown(int d,int l,int r) { if (!t[d].tag||l==r) return; int w=t[d].tag;t[d].tag=0
; t[d*2].tag+=w;t[d*2+1].tag+=w; t[d*2].mn+=w;t[d*2+1].mn+=w; } void ins(int d,int l,int r,int x,int y) { pushdown(d,l,r); if (l==r) {t[d].mn=min(t[d].mn,y);return;} int mid=(l+r)/2; if (x<=mid) ins(d*2,l,mid,x,y); else ins(d*2+1,mid+1,r,x,y); t[d].mn=min(t[d*2].mn,t[d*2+1].mn); } void modify(int d,int l,int r,int x,int y,int z) { if (x>y) return; pushdown(d,l,r); if (l==x&&r==y) {t[d].tag+=z;t[d].mn+=z;return;} int mid=(l+r)/2; modify(d*2,l,mid,x,min(y,mid),z); modify(d*2+1,mid+1,r,max(x,mid+1),y,z); t[d].mn=min(t[d*2].mn,t[d*2+1].mn); } int query(int d,int l,int r,int x,int y) { if (x>y) return inf; pushdown(d,l,r); if (l==x&&r==y) return t[d].mn; int mid=(l+r)/2; return min(query(d*2,l,mid,x,min(y,mid)),query(d*2+1,mid+1,r,max(x,mid+1),y)); } int main() { n=read(); for (int i=1;i<=n;i++) { s0[i]=s0[i-1];s1[i]=s1[i-1]; int x=read(); if (!x) s0[i]++; else s1[i]++; } m=read(); for (int i=1;i<=m;i++) a[i].first=read(),a[i].second=read(); sort(a+1,a+m+1); for (int i=1;i<=m;i++) vec[a[i].first].push_back(a[i].second); for (int i=1;i<=n*4+4;i++) t[i].mn=inf; ins(1,0,n,0,0); for (int i=1;i<=n;i++) { for (int j=0;j<vec[i].size();j++) ins(1,0,n,vec[i][j],query(1,0,n,0,vec[i][j])); if (s1[i]-s1[i-1]) modify(1,0,n,0,i-1,1); else modify(1,0,n,0,i-1,-1); } printf("%d",query(1,0,n,0,n)+s0[n]); return 0; }

相關推薦

AtCoder Regular Contest 085 F NRE 線段優化dp

題意 有長度為n初始全為0的陣列A和僅由0和1組成的陣列B。現在給出m個區間,每次可以選擇某個區間[l,r],使得A陣列下標在[l,r]之間的元素變為1。問A和B最小不同位置數量是多少。 n,m<=200000 分析 比賽的時候看成是區間取反,

AtCoder Regular Contest 075 E - Meaningful Mean 狀數組求順序對, 前綴和

n) cin 答案 bound std lan memset main ani 題目鏈接: http://arc075.contest.atcoder.jp/tasks/arc075_c 題意: 給你一個序列和一個數k,求有多少對l,r,使得a[l]+a[l+1]+...+

AtCoder Regular Contest 081 F - Flip and Rectangles

題目傳送門:https://arc081.contest.atcoder.jp/tasks/arc081_d 題目大意: 給定一個\(n×m\)的棋盤,棋盤上有一些黑點和白點,每次你可以選擇一行或一列,將上面所有的顏色取反,問若干次操作後可以得到的最大全黑子矩陣面積 首先我們可以發現,對於一個\(2×2

AtCoder Regular Contest 079 F

題意 給出一棵外向環套樹,問能否給每一個點定一個權值,使得每個點的權值都滿足其恰好是該點所有後繼節點的mex。 n<=200000 分析 對於不在環上的節點,它的權值是唯一確定的。對於環上的任意一個點,它的權值有兩種可能,一種是它的所有非環上後

降臨(線段優化dp

main spa space odi pri line 除了 發現 獲得 降臨 選定點i會有代價\(c_i\),如果一個區間j內的點全被選擇,就可以獲得回報\(p_j\)。點數和區間個數\(<1e5\)。 還以為是線段樹優化網絡流(50萬個點200萬條邊看上去很可

題解:CF115E(線段優化dp

定義 可能 bit tput space nbsp sans odi bsp 題目描述 你是一個賽車比賽的組織者,想在線性王國中安排一些比賽。 線性王國有n條連續的從左到右的道路。道路從左到右依次編號為從1到n,因此道路按照升序排列。在這些道路上可能會有幾場比賽,每一場

CF-833B The Bakery(線段優化Dp

imu ger another art 區間 produce let span start Some time ago Slastyona the Sweetmaid decided to open her own bakery! She bought r

luogu2605 基站選址 (線段優化dp)

設f[i][j]表示在第i個村莊建第j個基站的花費 那麼有$f[i][j]=min\{f[k][j-1]+w[k,i]\}$,其中w[k,i]表示在k,i建基站,k,i中間的不能被滿足的村莊的賠償金之和 如果把每個村莊能被滿足的區間處理出來,記做$[l_i,r_i]$,那麼i,j不能滿足的村莊,就是$i&

【題解】poj3171 Cleaning Shifts 線段優化DP

題目連結 Description Farmer John’s cows, pampered since birth, have reached new heights of fastidiousness. They now require their barn

BZOJ1835: [ZJOI2010]base 基站選址(線段優化Dp)

Description 有N個村莊坐落在一條直線上,第i(i>1)個村莊距離第1個村莊的距離為Di。需要在這些村莊中建立不超過K個通訊基站,在第i個村莊建立基站的費用為Ci。如果在距離第i個村莊不超過Si的範圍內建立了一個通訊基站,那麼就成它被覆蓋了。如果第i個村莊沒有被覆蓋,則需要向他們補償,

[ZJOI2010]基站選址(線段優化dp

坑待填。 \(Code\ Below:\) #include <bits/stdc++.h> #define lson (rt<<1) #define rson (rt<<1|1) using namespace std; const int maxn=20000+10

BZOJ 3790 神奇項鍊(迴文自動機+線段優化DP

我們預處理出來以i為結尾的最長迴文字尾(迴文自動機的構建過程中就可以求出)然後就是一個區間覆蓋,因為我懶得寫貪心,就寫了線段樹優化的DP。 #include<iostream> #include<cstring> #include<cstdio> #include<

POJ 2376 Cleaning Shifts (線段優化DP)

題目大意:給你很多條線段,開頭結尾是$[l,r]$,讓你覆蓋整個區間$[1,T]$,求最少的線段數 題目傳送門 線段樹優化$DP$裸題.. 先去掉所有能被其他線段包含的線段,這種線段一定不在最優解裡 排序,讓所有線段構成左右端點位置都遞增的排列 定義$f[i]$表示第$i$條線段,覆蓋到第$i$條線

BZOJ 1835 [ZJOI2010]基站選址 (線段優化DP)

geo har while 位置 如何 lse problem space getchar 題目大意:略 洛谷題面傳送門 BZOJ題面傳送門 註意題目的描述,是村莊在一個範圍內去覆蓋基站,而不是基站覆蓋村莊,別理解錯了 定義$f[i][k]$表示只考慮前i個村莊,一共建

bzoj1835(線段優化dp

神題啊,好吧,應該是因為我太弱了。。。 設f[i][k]表示到第i個村莊,第i個村莊一定會建基站,已經建了k個基站的最小費用. f[i][k]=min{f[j][k-1]+cost(j+1,i-1)}+c[i]; //注意本題線段樹維護的是當我們列舉i的時候,線段

線段優化DP】 HDU 3698 Let the light guide us

ans build tchar bit txt 。。 bre hellip har 這篇博客主要是發現了…… #define cmin(x,y) (x>y?x=y:0) 要比 void cmin(int &x,int y){i

CF940E Cashback 線段優化DP

## 題目描述 Since you are the best Wraith King, Nizhniy Magazin «Mir» at the centre of Vinnytsia is offering you a discount. You are given an array a a a of

Atcoder Regular contest 085F NRE 線段+DP

題意:給你兩個序列,a全部為0,b給出,給出一些區間,可以把a上的這些區間變為全1,要求操作以後兩個序列對應位置不相同的個數最小,n<=2e5. 說實話這種區間操作很容易想到線段樹,但是我沒想到

AtCoder Regular Contest 088 E - Papple Sort(狀數組+結論)

stream line sed post regular sum lib printf char   結論:每次把字符丟到最外面最優,用樹狀數組統計答案,把字符放到最外邊後可以當成消失了,直接在樹狀數組上刪掉就好。   感性理解是把字符丟到中間會增加其他字符的移動次數,但

[Atcoder Regular Contest 060] Tutorial

sts type link b- nbsp target AD SQ isp Link: ARC060 傳送門 C: #include <bits/stdc++.h> using namespace std; typedef long long ll; c