枚举,计算前缀和便可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; }