【AtCoder】ARC098題解

C - Attention

枚舉,計算前綴和便可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();
}

D - Xor Sum 2

等價與一個區間每一數位只能有一個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();
}

E - Range Minimum Queries

二分一個差值,枚舉最小值,咱們會獲得一個可取區間
對於枚舉的最小值,咱們把區間裏全部大於等於它的都標成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();
}

F - Donation

感受這道題和以前見過的某道題有點同樣,又不太同樣……
智商--,看了很久題解纔想明白一點。。。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;
}
相關文章
相關標籤/搜索