atcoder beginner 285 题解

比赛链接:https://atcoder.jp/contests/abc285

题解:
ABC
水题

	int a,b;
	scanf("%d%d",&a,&b);
	if(b==2*a||b==2*a+1)cout<<"Yes";
	else cout<<"No";
 	scanf("%d",&n);
	scanf("%s",s+1);
	for(int i=1;i<=n;i++)ans[i]=n-i;
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			int l=j-i;
			if(s[i] == s[j])
				ans[l]=min(ans[l],i-1);
		}
	}
	for(int i=1;i<=n-1;i++)printf("%d\n",ans[i]);
	scanf("%s",s+1);
	int n=strlen(s+1);
	for(int i=1;i<=n-1;i++){
		bs *= 26;
		ans+=bs;
	}
	bs=1;
	for(int i=n;i>=1;i--){
		ans+=(s[i] - 'A')*bs;
		bs*=26;
	}
	cout<<ans+1;

D
找环

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 2e5+5;

map<string,int>mp,trans;
vector<int>g[maxn];
pair<string,string> s[maxn];
int vis[maxn], gg = 0;

void dfs(int x,int pre=0){
	vis[x] = 1;
	for(int u : g[x])if(u != pre){
		if(vis[u]){gg = 1;return;}
		dfs(u, x);
		if(gg)return ;
	}
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>s[i].first>>s[i].second,
		mp[s[i].first] = mp[s[i].second] = 1;
	
	int cnt=0;
	for(auto now : mp){
		trans[now.first] = ++cnt;
	}
	for(int i=1;i<=n;i++){
		int i1 = trans[s[i].first], i2 = trans[s[i].second];
		g[i1].push_back(i2);
		g[i2].push_back(i1);
	}
	
	for(int i=1;i<=cnt;i++)if(!vis[i]){
		dfs(i);
		if(gg)return puts("No"), 0;
	}
	puts("Yes");

	return 0;
}

E
暴力dp

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 5005;

int n,a[maxn];
ll dp[maxn];
ll sum[maxn];

ll calc(int x,int y){
	// [x+1, y-1]
	if(y-x <= 1)return 0;
	int mid=(x+y)/2;
	// [x+1, mid] & [mid+1, y-1]
	int d0 = mid-x, d1 = y-mid-1;
	ll r1 = sum[d0], r2 = sum[d1];
	return r1+r2;
}

signed main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]), sum[i] = sum[i-1] + a[i];
	dp[0] = 0;
	for(int i=0;i<=n;i++){
		for(int j=i+1;j<=n;j++){
			dp[j] = max(dp[j], dp[i] + calc(i, j));
		}
	}
	cout<<dp[n];

	return 0;
}

F
vp的时候怒码线段树常数太大挂了
首先 \([l,r]\) 必须是单调的
另外注意还有字母个数的限制,比如abbccdde,那么bcd的个数必须和原来的串一致
因此只需要维护单调性和字母个数就行
单调性就考虑差分,如果 \(s_i \geq s_{i-1}, i \geq 2\) 那么就把 \(i\) 位置 +1,否则不变。修改也同理
字母个数也是一个单点修改求区间和就可以解决
开26+1个树状数组

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 2e5+5;

struct fen{
	int a[maxn];
	int N = -1;
	void init(int up){
		N = up;
	}
	
	int lb(int x){return x & (-x);}
	void add(int x,int del){	// init N!!!
		assert(N != -1);
		for(int i=x;i<=N;i+=lb(i)){
			a[i] += del;
		}
	}
	
	int query(int x){
		int res = 0;
		for(int i=x;i;i-=lb(i))res += a[i];
		return res;
	}
	int query(int l,int r){
		return query(r) - query(l-1);
	}
};
fen seq, oc[27];
int n;
char s[200005];

signed main(){
	scanf("%d",&n);
	scanf("%s",s + 1);
	int m;scanf("%d",&m);
	seq.init(n);
	for(int i=0;i<=25;i++)oc[i].init(n);
	
	for(int i=1;i<=n;i++){
		if(i>1 && s[i] >= s[i-1])seq.add(i, 1);
		oc[s[i] - 'a'].add(i, 1);
	}
	while(m --){
		int op;scanf("%d",&op);
		if(op == 1){
			int x; char ch;
			scanf("%d %c",&x,&ch);
			if(x>=2 && s[x]>=s[x-1])seq.add(x, -1);
			if(x<=n-1 && s[x]<=s[x+1])seq.add(x+1, -1);
			if(x>=2 && ch>=s[x-1])seq.add(x, 1);
			if(x<=n-1 && ch<=s[x+1])seq.add(x+1, 1);
			
			oc[s[x] - 'a'].add(x, -1);
			oc[ch - 'a'].add(x, 1);
			
			s[x] = ch;
		}else{
			int l, r;scanf("%d%d",&l,&r);
			if(seq.query(l+1, r) != r-l){
				puts("No");
				continue;
			}
			int i1 = s[l]-'a', i2 = s[r]-'a', gg = 0;
			for(int i=i1+1;i<=i2-1;i++){
				if(oc[i].query(l, r) != oc[i].query(1, n)){
					gg = 1;
					break;
				}
			}
			if(gg)puts("No");
			else puts("Yes");
		}
	}

	return 0;
}

G
考虑了一下普通的图论做法好像没法做,想到网络流
注意网格图是个天然的二分图(只有 \(i+j\) 奇偶性不同的点才能连边)
\((i,j)\) 能向 \((i,j+1) 或 (i+1,j)\) 连边 iff 两个点都没有 1
显然我们只需要关心所有的 2 是否有地方放,这就是一个匹配问题!
因为我们要求所有的 2 必须匹配,因此可以考虑将 \((S,这个点)\) 或者 \((这个点,T)\) 的容量下限设为 1,然后对于所有的边的容量上限均设为1,跑上下界可行流

// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define pii pair<int,int>

using namespace std;

typedef long long ll;
typedef long long LL;

const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 2e5+5;

int n,m;
struct ed{
	LL from,to,cap,flow,rev;
	ed(){}
	ed(LL from,LL to,LL cap,LL flow,LL rev):from(from),to(to),cap(cap),flow(flow),rev(rev){}
};
vector<ed>g[maxn];

struct netflow{
	int cur[maxn]; 
	int d[maxn], q[maxn], hd, tl;
	int in[maxn], out[maxn];
	int s, t;	// 源 汇 
	
	netflow(){s=t=-1;}
	
	void clear(){
		s = t = -1;
		for(int i=1;i<=n+m+10;i++)g[i].clear(), in[i] = out[i] = 0;
	}
	
	void init(int s0,int t0){
		s = s0, t = t0;
	}

	void add(int x,int y,LL v){
		g[x].push_back(ed(x,y,v,0,g[y].size()));
		g[y].push_back(ed(y,x,0,0,g[x].size() - 1));
	}
	
	void adde(int x,int y,int l,int r){	// x->y [l,r]
		add(x, y, r-l);
		out[x] += l; in[y] += l;
	}
	
	int bfs(){
		memset(d,0, sizeof d);
		hd = tl = 0;
		q[tl ++] = s;
		d[s] = 1;
		while(hd != tl){
			int now = q[hd ++];
			for(int i = 0;i<g[now].size();i++){
				ed &e = g[now][i];
				if(!d[e.to] && e.cap > e.flow)d[e.to] = d[now] + 1, q[tl ++] = e.to;
			}
		}
		return d[t];
	}
	
	LL dfs(int now,LL rem){	// rem 当前流量 
		if(now == t || !rem)return rem;
		LL flow = 0;
		for(int &i = cur[now]; i < g[now].size();i ++){
			ed &e = g[now][i];
				// 分层图 & 残量不为0 
			if(d[e.to] == d[now] + 1 && e.cap > e.flow){
				LL f = dfs(e.to, min(rem, e.cap - e.flow));
				rem -= f, flow += f, e.flow += f, g[e.to][e.rev].flow -= f;
			}
			if(!rem)break;
		}
		if(rem)d[now] = -1;
		return flow;
	}
	
	LL dinic(){
		assert(s!=-1);
		LL flow = 0;
		while(bfs()){
			memset(cur, 0, sizeof cur);
			flow += dfs(s, 1ll << 62);
		}
		return flow;
	}
	
	LL pflow(int S0, int T0, int S, int T, int point){	// possible flow
		// S0 T0 源点汇点 ST 超源超汇 point 有多少点 
		LL lim = 0;
		for(int i=1;i<=point;i++){
			int cur = in[i] - out[i];
			if(in[i] == out[i] && in[i] == 0)continue;
			if(cur > 0)add(S, i, cur), lim += cur;
			else add(i, T, -cur);
		}
		add(T0, S0, inf);
		init(S, T);
		LL res = dinic();
		if(res < lim)return -1;
		init(S0, T0);
		return dinic();
	}
}nf;
int S0, T0, S, T;
int h,w;
char s[305][305];

int ind(int x,int y){return (x-1) * w + y;}
int rnd(int x,int y){
	if(s[x][y] == '2')return 1;
	return 0;
}
signed main(){
	scanf("%d%d",&h,&w);
	S0 = h*w+1, T0 = h*w+2, S = h*w+3, T = h*w+4;
	for(int i=1;i<=h;i++)scanf("%s",s[i] + 1);
	for(int i=1;i<=h;i++)
		for(int j=1;j<=w;j++)if(s[i][j] != '1'){
			if((i+j) & 1){
				int le = rnd(i, j);
				nf.adde(ind(i, j), T0, le, 1);
			}else{
				int le = rnd(i, j);
				nf.adde(S0, ind(i, j), le, 1);
			}
		}
	for(int i=1;i<=h;i++)
		for(int j=1;j<=w;j++)if(s[i][j] != '1'){
			if(i+1<=h && s[i+1][j] != '1'){
				int x1 = ind(i,j),x2 = ind(i+1,j);
				if((i+j)&1)swap(x1, x2); 
				nf.adde(x1, x2, 0, 1);
			}
			if(j+1<=w && s[i][j+1] != '1'){
				int x1 = ind(i,j), x2 = ind(i, j+1);
				if((i+j)&1)swap(x1, x2);
				nf.adde(x1, x2, 0, 1);
			}
		}
	ll res = nf.pflow(S0, T0, S, T, h*w+2);
	puts(~res ? "Yes" : "No");

	return 0;
}
posted @ 2023-01-18 16:09  SkyRainWind  阅读(110)  评论(0编辑  收藏  举报