【AtCoder】AGC029(A-E)

A - Irreversible operation

题解

把每个B后面的W个数累加起来即可

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 1000005
//#define ivorysi
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) {x = -x;putchar('-');}
    if(x >= 10) {
    out(x / 10);
    }
    putchar('0' + x % 10);
}

char s[200005];
int64 ans = 0;
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    scanf("%s",s + 1);
    int64 t = 0;
    int N = strlen(s + 1);
    for(int i = N ; i >= 1 ; --i) {
        if(s[i] == 'W') ++t;
        else ans += t;
    }
    out(ans);enter;
}

B - Powers of two

题解

这比赛打的太难受了

这个我花了一个树结构,蒙了一个dp,然后wa了,去硬上T2

最后发现我把一个N改成离散化后的tot就A了

就是考虑一个点,和它组成恰好大于它的\(2^{i}\)的值只有一个,构成了一片森林,对于每个森林从底向上更新,如果父亲和儿子能配对就尽可能多的配对

每个\(2^{i}\)的点若有剩余再两两配对

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 200005
//#define ivorysi
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) {x = -x;putchar('-');}
    if(x >= 10) {
	out(x / 10);
    }
    putchar('0' + x % 10);
}
struct node {
    int to,next;
}E[MAXN * 10];
map<int,int> mm;
int val[MAXN],A[MAXN],N,tot,ans;
int head[MAXN],sumE,dp[MAXN];
bool vis[MAXN];
int lowbit(int x) {
    return x & (-x);
}
void add(int u,int v) {
    E[++sumE].to = v;
    E[sumE].next = head[u];
    head[u] = sumE;
}
void Init() {
    read(N);
    for(int i = 1 ; i <= N ; ++i) {
        read(A[i]);
        val[i] = A[i];
        mm[A[i]]++;
    }
    sort(val + 1,val + N + 1);
    tot = unique(val + 1,val + N + 1) - val - 1;
    for(int i = 1 ; i <= N ; ++i) {
        int a = val[i];
        int k = lower_bound(val + 1,val + tot + 1,a) - val;
        for(int64 t = 1 ; t <= 1073741824 ; t <<= 1) {
            if(t > 2 * a) {
                if(mm[t - a] == 0) continue;
                int h = lower_bound(val + 1,val + tot + 1,t - a) - val;
                add(k,h);
            }
        }
    }

}
void dfs(int u) {
    vis[u] = 1;
    dp[u] = mm[val[u]];
    for(int i = head[u] ; i ; i = E[i].next) {
        int v = E[i].to;
        if(!vis[v]) {
            dfs(v);
            int t = min(dp[u],dp[v]);
            dp[u] -= t;
            dp[v] -= t;
            ans += t;
        }
    }
}
void Solve() {
    for(int i = 1 ; i <= tot ; ++i) {
        if(!vis[i]) dfs(i);
        if(lowbit(val[i]) == val[i]) ans += dp[i] / 2;
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Init();
    Solve();
}

C - Lexicographic constraints

题解

好不容易想到了一个分段维护一个字符个数进制下的数

没想到二分,gg了

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 200005
//#define ivorysi
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) {x = -x;putchar('-');}
    if(x >= 10) {
    out(x / 10);
    }
    putchar('0' + x % 10);
}
int N;
int A[MAXN];
int pw[MAXN][25],cnt[MAXN],ans;
vector<pii > v;
void Init() {
    read(N);
    for(int i = 1 ; i <= N ; ++i) read(A[i]);
    cnt[1] = 1000000000;
    for(int i = 1 ; i <= N ; ++i) {
        pw[i][0] = 1;
        for(int j = 1 ; j <= 20 ; ++j) {
            if(pw[i][j - 1]  > N / i) {
                cnt[i] = j - 1;break;
            }
            pw[i][j] = pw[i][j - 1] * i;
        }
    }
}
bool check(int mid) {
    v.clear();
    v.pb(mp(A[1],0));int sum = A[1];
    for(int i = 2 ; i <= N ; ++i) {
	if(A[i] <= A[i - 1]) {
	    if(mid == 1) return false;
	    if(sum < A[i - 1]) {v.pb(mp(A[i - 1] - sum,0));sum = A[i - 1];}
	    int s = v.size() - 1;
	    for(int k = s ; k >= 0 ; --k) {
		if(sum - v[k].fi >= A[i]) {sum -= v[k].fi;v.pop_back();}
		else {
		    int t = sum - A[i];
		    if(t > cnt[mid]) v[k].se = 0;
		    else v[k].se /= pw[mid][t];
		    v[k].fi -= t;
		    sum = A[i];
		}
		if(sum == A[i]) break;
	    }
	    s = v.size() - 1;
	    for(int k = s ; k >= 0 ; --k) {
		if(v[k].fi <= cnt[mid]) {
		    if(v[k].se + 1 < pw[mid][v[k].fi]) {++v[k].se;break;}
		    else {
			v[k].se = 0;if(k == 0) return false;
		    }
		}
		else {++v[k].se;break;}
	    }
	}
    }
    return true;
}
void Solve() {
    int l = 1,r = N;
    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();
}

D - Grid game

题解

这题好水啊= =开D我就win了啊,sdC一直不过太难受了啊

就是考虑我们肯定是走到某个障碍物上面,游戏结束了

如何判断能不能走到呢,首先如果这一列是\(j\),我们所在的行\(i\)必须大于等于\(j\),如果有一个连成一串的障碍物从\((j,j)\)开始往下压

每次最多压了多少,就是当前列最靠下不能走的点\(h\),求一个\(t = h - i + 1\)

\(t\)每次取一个前缀\(max\),然后对于每一列把行大于等于\(j + t\)的障碍物都设成不合法即可

把每一列能走到最靠上的障碍物取一个\(min\)

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 200005
//#define ivorysi
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) {x = -x;putchar('-');}
    if(x >= 10) {
    out(x / 10);
    }
    putchar('0' + x % 10);
}
int H,W,N;
vector<int> v[MAXN];
bool pass[MAXN];
void Solve() {
    read(H);read(W);read(N);
    int x,y;
    for(int i = 1 ; i <= N ; ++i) {
	read(x);read(y);
	v[y].pb(x);
    }
    for(int i = 1 ; i <= W ; ++i) v[i].pb(H + 1);
    sort(v[1].begin(),v[1].end());
    int ans = v[1][0] - 1;
    int t = 0;
    for(int i = 2 ; i <= W ; ++i) {
	sort(v[i].begin(),v[i].end());
	int s = v[i].size();
	int m = 0;
	for(int k = 0 ; k < s ; ++k) {
	    if(v[i][k] <= i + t) {pass[v[i][k]] = 1;m = max(v[i][k],m);}
	    else if(pass[v[i][k] - 1]) {pass[v[i][k]] = 1;m = max(v[i][k],m);}
	    else {
		ans = min(ans,v[i][k] - 1);
		break;
	    }
	}
	t = max(t,m - i + 1);
    }
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}

E - Wandering TKHS

题解

关注一下一个路径的根缀最大值

把根缀最大值相同的部分挑出来

我们发现一个根缀最大值是\(u\)\(u\)的某个儿子是\(v\)\(v\)中的所有节点要走到\(u\),就要经过\(v\)中所有根缀最大值为\(u\)的部分,这个可以差分实现

而根缀最大值自身讨论起来有点麻烦,直接搜索即可

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define pdi pair<db,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define eps 1e-8
#define mo 974711
#define MAXN 200005
//#define ivorysi
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) {x = -x;putchar('-');}
    if(x >= 10) {
    out(x / 10);
    }
    putchar('0' + x % 10);
}
int N;
struct node {
    int to,next;
}E[MAXN * 2];
int head[MAXN],sumE;
int mv[MAXN],siz[MAXN],d[MAXN],c[MAXN],son[MAXN];
void add(int u,int v) {
    E[++sumE].next = head[u];
    E[sumE].to = v;
    head[u] = sumE;
}
void calc(int u,int fa,int val) {
    son[u] = 1;
    for(int i = head[u] ; i ; i = E[i].next) {
	int v = E[i].to;
	if(v != fa && v < val) {
	    calc(v,u,val);
	    son[u] += son[v];
	}
    }
}
void dfs(int u,int fa) {
    mv[u] = max(mv[fa],u);
    siz[u] = 1;
    for(int i = head[u] ; i ; i = E[i].next) {
	int v = E[i].to;
	if(v != fa) {
	    dfs(v,u);
	    siz[u] += siz[v];
	    d[u] += d[v];
	}
    }
    if(mv[u] == u) {
	calc(u,fa,mv[fa]);
	d[u] = -siz[u];
    }
    if(mv[fa] == fa) d[u] += siz[u];
}
void dfs2(int u,int fa) {
    if(fa) {
	if(mv[u] == u) {c[u] += son[u];}
	else if(mv[fa] == fa) {c[u] -= son[u];c[u] += d[u];}
	c[u] += c[fa];
    }
    for(int i = head[u] ; i ; i = E[i].next) {
	int v = E[i].to;
	if(v != fa) {
	    dfs2(v,u);
	}
    }
}
void Init() {
    read(N);
    int x,y;
    for(int i = 1 ; i < N ; ++i) {
	read(x);read(y);add(x,y);add(y,x);
    }
}
void Solve() {
    dfs(1,0);
    dfs2(1,0);
    for(int i = 2 ; i <= N ; ++i) {
	out(c[i]);
	i == N ? enter : space;
    }
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Init();
    Solve();
}

F - Construction of a tree

\(2 \cdot 10^{5}\)的网络流,有毒,不会卡常,弃疗了,再见

posted @ 2018-12-21 17:18  sigongzi  阅读(1289)  评论(0编辑  收藏  举报