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;
}