枚舉,計算前綴和便可node
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define space putchar(' ') #define enter putchar('\n') #define mp make_pair #define pb push_back #define MAXN 300005 //#define ivorysi using namespace std; typedef long long int64; template<class T> void read(T &res) { res = 0;T f = 1;char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0){putchar('-');x = -x;} if(x >= 10) out(x / 10); putchar('0' + x % 10); } int N,sum[2][MAXN]; char s[MAXN]; void Solve() { read(N); scanf("%s",s + 1); for(int i = 1 ; i <= N ; ++i) { sum[0][i] = sum[0][i - 1];sum[1][i] = sum[1][i - 1]; if(s[i] == 'E') sum[0][i]++; else sum[1][i]++; } int ans = N; for(int i = 1 ; i <= N ; ++i) { ans = min(i - 1 - sum[0][i - 1] + (N - i - (sum[1][N] - sum[1][i])),ans); } out(ans);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); }
等價與一個區間每一數位只能有一個1c++
咱們記錄\(nxt[i][j]\)表示第\(i\)位數下一個第\(j\)位是1的位置是什麼spa
咱們枚舉左端點,而後去計算右端點,取最小的右端點code
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define space putchar(' ') #define enter putchar('\n') #define mp make_pair #define pb push_back #define MAXN 200005 //#define ivorysi using namespace std; typedef long long int64; template<class T> void read(T &res) { res = 0;T f = 1;char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0){putchar('-');x = -x;} if(x >= 10) out(x / 10); putchar('0' + x % 10); } int N,a[MAXN],nxt[MAXN][25]; void Solve() { read(N); for(int i = 1 ; i <= N ; ++i) read(a[i]); for(int i = 0 ; i < 20 ; ++i) nxt[N + 1][i] = N + 1; for(int i = N ; i >= 1 ; --i) { for(int j = 0 ; j < 20 ; ++j) { if(a[i] >> j & 1) { nxt[i][j] = i; } else nxt[i][j] = nxt[i + 1][j]; } } int64 ans = 0; for(int i = 1 ; i <= N ; ++i) { int r = N; for(int j = 0 ; j < 20 ; ++j) { int t = nxt[i][j]; if(t != N + 1) r = min(r,nxt[t + 1][j] - 1); } ans += (r - i + 1); } out(ans);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Solve(); }
二分一個差值,枚舉最小值,咱們會獲得一個可取區間
對於枚舉的最小值,咱們把區間裏全部大於等於它的都標成1,對於一段連續的1區間,統計一下區間裏有多少個數在範圍內,記爲\(cnt\),設長度爲L,這個區間能夠知足的詢問個數就是\(min(L - K + 1,cnt)\)get
#include <bits/stdc++.h> #define fi first #define se second #define pii pair<int,int> #define mp make_pair #define pb push_back #define space putchar(' ') #define enter putchar('\n') #define MAXN 2005 //#define ivorysi using namespace std; typedef long long int64; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {x = -x;putchar('-');} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } int N,K,Q; int a[MAXN],val[MAXN],tot; bool check(int mid) { for(int i = 1 ; i <= tot ; ++i) { int l = val[i],r = val[i] + mid; int res = 0,st = 0,ed = -1,cnt = 0; for(int j = 1 ; j <= N ; ++j) { if(a[j] >= l) { if(!st) st = ed = j; ed = max(ed,j); if(a[j] <= r) ++cnt; } else { if(ed - st + 1 >= K) { res += min(cnt,(ed - st + 1) - K + 1); } st = 0,ed = -1;cnt = 0; } } if(ed - st + 1 >= K) { res += min(cnt,(ed - st + 1) - K + 1); } if(res >= Q) return true; } return false; } void Init() { read(N);read(K);read(Q); for(int i = 1 ; i <= N ; ++i) { read(a[i]); val[i] = a[i]; } sort(val + 1,val + N + 1); tot = unique(val + 1,val + N + 1) - val - 1; } void Solve() { int L = 0,R = val[tot] - val[1]; while(L < R) { int mid = (L + R) >> 1; if(check(mid)) R = mid; else L = mid + 1; } out(L);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Init(); Solve(); }
感受這道題和以前見過的某道題有點同樣,又不太同樣……
智商--,看了很久題解纔想明白一點。。。it
就是……咱們先想一下,咱們若是按照每一個點交錢的順序寫下一個序列
對於第k次選走的點,咱們須要的是咱們錢數\(w\),須要有\(w >= \sum_{i = 1}^{k}B_{id[i]} + max(A_{id[k]} - B_{id[k]},0)\)
最後咱們須要的是序列最大值,咱們要最大值最小io
而且,要求這個序列付完錢的點,以後不會再通過了class
咱們對於每一個點求一個\(C[i]\)爲\(max(A[i] - B[i],0)\)遍歷
咱們發現,若是一個在\(C[i]\)最大值被選擇以前,答案的下限在不斷提升im
那麼咱們可能會考慮到,咱們要拿走u點以後,咱們的圖可能會裂成不少子圖,咱們須要進入其中一個子圖,而後將剩下子圖的B連帶u點累加起來加上\(C[u]\)來累加答案
那麼,在最大值拿走以前,假設最大值拿走以後咱們進入的子圖是\(G_{i}\),那麼,\(G_{i}\)裏的任何一點\(w\)爲何不能先於u以前拿走呢?
這是我很難想明白的一件事,我如今也許能談一下理解
當\(w\)點在\(u\)以前時,\(B[w]\)一定會被統計到答案的一個下限中,若是\(w\)在\(u\)點以後,\(B[w]\)可能不會累加進最後的答案用來更新,也可能會,而咱們但願的是答案更優秀,\(w\)在\(u\)以前答案不可能變小,而\(w\)在\(u\)以後,答案可能會變小可是絕對不會變大,因此咱們把其餘子圖訪問完以後選擇訪問這個子圖
咱們發現,這剛恰好是一個子問題,咱們對這個子圖取出最大值做爲根,而後從新求一下這個子圖的答案就能夠,咱們能夠用dp解決這個問題,對於每一個子圖都進入一遍求值
然而,好像又有了一個新的問題,咱們怎麼求每次去掉最大值後,每一個子圖裏的最大值,暴力求顯然是\(n^2\)的
咱們發現,全局最大值和每一個子圖裏的最大值連邊,每一個子圖裏的最大值和去掉最大值後新裂成的子圖最大值連邊,恰好能夠在圖中構建出一棵樹
而C值最小的點,必然是葉子
咱們按C從小到大遍歷每一個點,訪問周邊的全部點,若是周邊的點有C值小於它的,就讓周邊的點所在的子圖的最大值(用並查集維護)做爲它的兒子就行了
寫出來的代碼很是清晰,又簡單好寫,思惟含量又高,能夠說是虐我這種蒟蒻的好題了。
#include <bits/stdc++.h> //#define ivorysi #define enter putchar('\n') #define space putchar(' ') #define fi first #define se second #define pb push_back #define mp make_pair #define eps 1e-8 #define mo 974711 #define MAXN 200005 #define pii pair<int,int> using namespace std; typedef long long int64; typedef double db; template<class T> void read(T &res) { res = 0;char c = getchar();T f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { res = res * 10 + c - '0'; c = getchar(); } res *= f; } template<class T> void out(T x) { if(x < 0) {putchar('-');x = -x;} if(x >= 10) { out(x / 10); } putchar('0' + x % 10); } int N,M; struct node { int to,next; }E[MAXN * 2]; int head[MAXN],sumE,id[MAXN],ra[MAXN],f[MAXN]; int64 A[MAXN],B[MAXN],C[MAXN],dp[MAXN],siz[MAXN]; vector<int> son[MAXN]; int getfa(int x) { return f[x] == x ? x : f[x] = getfa(f[x]); } bool cmp(int s,int t) { return C[s] < C[t]; } void add(int u,int v) { E[++sumE].to = v; E[sumE].next = head[u]; head[u] = sumE; } void Init() { read(N);read(M); for(int i = 1 ; i <= N ; ++i) { read(A[i]);read(B[i]);C[i] = max(A[i] - B[i],0LL); id[i] = i; } sort(id + 1,id + N + 1,cmp); for(int i = 1 ; i <= N ; ++i) ra[id[i]] = i; int u,v; for(int i = 1 ; i <= M ; ++i) { read(u);read(v); add(u,v);add(v,u); } } void dfs1(int u) { siz[u] += B[u]; for(auto v : son[u]) { dfs1(v); siz[u] += siz[v]; } } void dfs2(int u) { if(son[u].size() == 0) { dp[u] = B[u] + C[u]; return; } dp[u] = 1e18; for(auto v : son[u]) { dfs2(v); dp[u] = min(siz[u] - siz[v] + max(C[u],dp[v]),dp[u]); } } void Solve() { for(int i = 1 ; i <= N ; ++i) f[i] = i; for(int i = 1 ; i <= N ; ++i) { int u = id[i]; for(int j = head[u] ; j ; j = E[j].next) { int v = E[j].to; if(ra[getfa(v)] < ra[u] && getfa(v) != u) { son[u].pb(getfa(v)); f[getfa(v)] = u; } } } dfs1(id[N]); dfs2(id[N]); out(dp[id[N]]);enter; } int main() { #ifdef ivorysi freopen("f1.in","r",stdin); #endif Init(); Solve(); return 0; }