A:如果C在D左侧,显然先让B到达终点再让A走即可,否则先判断一下A是否可以在某处超过B。也就是先判断一下起点与终点之间是否有连续的障碍,若有则无解;然后若C在D左侧输出Yes,否则判断B和D之间是否有存在某个空地其左右均为空地,若有则输出Yes,否则输出No。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 200010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,a,b,c,d;
char s[N];
signed main()
{
n=read(),a=read(),b=read(),c=read(),d=read();
scanf("%s",s+1);
for (int i=1;i<n;i++) if (s[i]=='#'&&s[i+1]=='#'&&(a<=i&&c>i||b<=i&&d>i)) {cout<<"No";return 0;}
if (c>d)
{
int pos=-1;
for (int i=b;i<=d;i++) if (s[i-1]=='.'&&s[i]=='.'&&s[i+1]=='.') {pos=i;break;}
if (pos==-1) {cout<<"No";return 0;}
else cout<<"Yes";
}
else cout<<"Yes";
return 0;
//NOTICE LONG LONG!!!!!
}

  B:考虑每个BC能与哪些A一起做出贡献,显然这样的A应在该BC前面,且它们之间只有A和连续出现的BC出现。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 200010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n;
char s[N];
signed main()
{
int cnt=0;ll ans=0;
scanf("%s",s+1);n=strlen(s+1);
for (int i=1;i<=n;i++)
if (s[i]=='A') cnt++;
else if (s[i]=='B')
{
if (s[i+1]=='C') i++,ans+=cnt;
else cnt=0;
}
else cnt=0;
cout<<ans;
return 0;
//NOTICE LONG LONG!!!!!
}

  C:首先显然的是每门课权重要么取max要么取min,其中学的比对方多时取max,比对方少时取min。

  然后注意到最多只有一门课不学满,其它课要么学满要么不学,因为假设最优解中有超过一门课不学满,显然将其中权重低的改为权重高的不会使答案更劣。

  假设固定了某一门课不学满及学多少,对于剩余的课,将学满获得的收益减去不学获得的减益定义为价值,按价值从高到低依次选择学满即可。

  这个过程可以改为先按价值排序,求出假设要么不学要么学满,最优要学满哪些课程才能满足条件,然后原问题的最优解显然是从这些学满的课程中删去一个再学习某个课程。

  如果删去的不是被选中的课程中价值最低的,最优方案一定不会是选择其他课程,因为显然不优;而如果是价值最低的,可以枚举所有其他课程进行选择。先二分一下答案就好了。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 100010
#define int long long
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,m,pos;
ll ans,s[N],tot;
struct data
{
int x,l,r;
bool operator <(const data&a) const
{
return 1ll*(m-x)*r+1ll*x*l>1ll*(m-a.x)*a.r+1ll*a.x*a.l;
}
}a[N];
ll mxval(int i){return 1ll*(m-a[i].x)*a[i].r;}
ll val(int i,int k){if (k<a[i].x) return 1ll*(k-a[i].x)*a[i].l;else return 1ll*(k-a[i].x)*a[i].r;}
bool check(int k,ll tot)
{
for (int i=1;i<pos;i++)
if (tot-mxval(i)+val(i,k)>=0) return 1;
tot-=mxval(pos);tot+=val(pos,0);
for (int i=pos;i<=n;i++)
if (tot-val(i,0)+val(i,k)>=0) return 1;
return 0;
}
signed main()
{
n=read(),m=read();
for (int i=1;i<=n;i++) a[i].x=read(),a[i].l=read(),a[i].r=read();
sort(a+1,a+n+1);
for (int i=n;i>=1;i--) s[i]=s[i+1]-val(i,0);
tot=0;pos=0;
for (int i=1;i<=n;i++)
{
tot+=mxval(i);
if (tot>=s[i+1]) {pos=i;break;}
}
if (pos==0) {cout<<0;return 0;}
tot-=s[pos+1];
int l=0,r=m;
while (l<=r)
{
int mid=l+r>>1;
if (check(mid,tot)) ans=mid,r=mid-1;
else l=mid+1;
}
cout<<ans+1ll*(pos-1)*m;
return 0;
//NOTICE LONG LONG!!!!!
}

  D:直接暴力跑费用流边的数量过多。注意到|x1-x2|+|y1-y2|=max{(x1+y1)+(-x2-y2),(x1-y1)+(-x2+y2),(-x1+y1)+(x2-y2),(-x1-y1)+(x2+y2)},于是可以看成是给每个点在四种颜色中选择一种颜色,不同点的不同颜色价值不同,要求两组点中四种颜色出现次数均相同,最大化价值和。这个东西可以费用流,即两排点分别对应两组点,中间四个点表示四种颜色,源汇对应向两组点连边,容量为该坐标对应的点的数量,费用为0;两组点分别向四种颜色连边,容量inf,费用为该点取该颜色时的价值的相反数。这样边数就是O(n)的,跑费用流即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 2010
#define S 0
#define T 2001
#define red(x) (x)
#define blue(x) (n+(x))
#define id(x) (2002+(x))
#define int long long
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,p[N],d[N],q[N],pre[N],t=-1,ans;
bool flag[N];
struct data{int x,y,c,v[4];
}a[N],b[N];
struct data2{int to,nxt,cap,flow,cost;
}edge[N<<5];
void addedge(int x,int y,int z,int cost)
{
t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].cap=z,edge[t].flow=0,edge[t].cost=cost,p[x]=t;
t++;edge[t].to=x,edge[t].nxt=p[y],edge[t].cap=0,edge[t].flow=0,edge[t].cost=-cost,p[y]=t;
}
int inc(int &x){x++;if (x>2007) x-=2007;return x;}
bool spfa()
{
memset(d,60,sizeof(d));d[S]=0;
memset(flag,0,sizeof(flag));
int head=0,tail=1;q[1]=S;
do
{
int x=q[inc(head)];flag[x]=0;
for (int i=p[x];~i;i=edge[i].nxt)
if (edge[i].flow<edge[i].cap&&d[x]+edge[i].cost<d[edge[i].to])
{
d[edge[i].to]=d[x]+edge[i].cost;
pre[edge[i].to]=i;
if (!flag[edge[i].to]) q[inc(tail)]=edge[i].to,flag[edge[i].to]=1;
}
}while (head!=tail);
return d[T]<10000000000000000ll;
}
void ekspfa()
{
while (spfa())
{
int v=n;
for (int i=T;i!=S;i=edge[pre[i]^1].to)
v=min(v,edge[pre[i]].cap-edge[pre[i]].flow);
for (int i=T;i!=S;i=edge[pre[i]^1].to)
edge[pre[i]].flow+=v,edge[pre[i]^1].flow-=v,ans+=v*edge[pre[i]].cost;
}
}
signed main()
{
n=read();memset(p,255,sizeof(p));
for (int i=1;i<=n;i++)
{
a[i].x=read(),a[i].y=read(),a[i].c=read();
a[i].v[0]=a[i].x+a[i].y;
a[i].v[1]=a[i].x-a[i].y;
a[i].v[2]=-a[i].x+a[i].y;
a[i].v[3]=-a[i].x-a[i].y;
}
for (int i=1;i<=n;i++)
{
b[i].x=read(),b[i].y=read(),b[i].c=read();
b[i].v[0]=-b[i].x-b[i].y;
b[i].v[1]=-b[i].x+b[i].y;
b[i].v[2]=b[i].x-b[i].y;
b[i].v[3]=b[i].x+b[i].y;
}
for (int i=1;i<=n;i++)
{
addedge(S,red(i),a[i].c,0),addedge(blue(i),T,b[i].c,0);
for (int j=0;j<4;j++)
addedge(red(i),id(j),a[i].c,-a[i].v[j]),addedge(id(j),blue(i),b[i].c,-b[i].v[j]);
}
ekspfa();
cout<<-ans;
return 0;
//NOTICE LONG LONG!!!!!
}

  E:枚举一个根,然后O(n)check。显然将两个点一个往上拉一个往下拉没有任何意义,所以如果有解答案就为所有棋子的深度之和/2。于是只要判断是否有解。

  同样显然的一点是对于根来说可以在其各儿子子树内部操作完后再进行子树间的操作,这样不会造成负面影响。于是可以划分成子问题了。设f[i]为i子树内部移动后深度之和的最小值,d[i]为i子树中所有棋子的深度之和,显然内部操作过程中f[i]~d[i]之间所有与d[i]奇偶性相同的深度之和都能被取到。f[root]=0时即有解。

  考虑转移,先将f[son]和d[son]变为以i为根情况下的值,然后相当于要对每个儿子决定一个f[]~d[]之间变量x[](可以和d[]奇偶性不同,因为子树间可以相互匹配,不考虑奇偶性产生的误差至多为1,而实际上这不造成影响),最小化max{x[son]}*2-Σx[son]。当然这个值还要对d[i]%2取max。假设固定了max{x},要最小化该值,显然其他变量的取值均应为min(x,d[])。容易发现max{x}取d[]中的次大值时最优。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 1000000010
#define N 2010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int read()
{
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int n,p[N],a[N],t,deep[N],size[N],sigmadeep[N],f[N],root,ans=inf;
struct data{int to,nxt;
}edge[N<<1];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void dfs(int k,int from)
{
size[k]=a[k];sigmadeep[k]=a[k]*deep[k];
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from)
{
deep[edge[i].to]=deep[k]+1;
dfs(edge[i].to,k);
size[k]+=size[edge[i].to];
sigmadeep[k]+=sigmadeep[edge[i].to];
}
}
void work(int k,int from)
{
int son=0;f[k]=0;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from) son++,work(edge[i].to,k);
if (son==0) f[k]=0;
else
{
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from) sigmadeep[edge[i].to]+=size[edge[i].to],f[edge[i].to]+=size[edge[i].to];
if (son==1)
{
int s=0;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from) s=f[edge[i].to];
f[k]=s;
}
else
{
int mx1=-1,mx2=-1;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from)
if (sigmadeep[edge[i].to]>mx1) mx2=mx1,mx1=sigmadeep[edge[i].to];
else mx2=max(mx2,sigmadeep[edge[i].to]);
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from) mx2=max(mx2,f[edge[i].to]);
f[k]=mx2*2;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from) f[k]-=min(mx2,sigmadeep[edge[i].to]);
}
f[k]=max(f[k],sigmadeep[k]&1);
}
}
//若干个f[]~sigmadeep[]之间的变量,最小化max{x}*2-Σx
//枚举maxx 后,后一部分即Σmin(x,sigmadeep)
//x应取次大deep
signed main()
{
n=read();
for (int i=1;i<=n;i++) if (getc()=='0') a[i]=0;else a[i]=1;
for (int i=1;i<n;i++)
{
int x=read(),y=read();
addedge(x,y),addedge(y,x);
}
for (int i=1;i<=n;i++)
{
memset(deep,0,sizeof(deep));
memset(size,0,sizeof(size));
memset(sigmadeep,0,sizeof(sigmadeep));
memset(f,42,sizeof(f));
dfs(i,i);
for (int j=1;j<=n;j++) sigmadeep[j]-=size[j]*deep[j];
if (sigmadeep[i]&1) continue;
work(i,i);
/*for (int j=1;j<=n;j++) cout<<deep[j]<<' ';cout<<endl;
for (int j=1;j<=n;j++) cout<<size[j]<<' ';cout<<endl;
for (int j=1;j<=n;j++) cout<<sigmadeep[j]<<' ';cout<<endl;
for (int j=1;j<=n;j++) cout<<f[j]<<' ';cout<<endl;cout<<endl;*/
if (f[i]==0) ans=min(ans,sigmadeep[i]/2);
}
if (ans==inf) cout<<-1;else cout<<ans;
return 0;
//NOTICE LONG LONG!!!!!
}
//假设确定根
//f[i]将i子树内的点都移到lca的最小深度之和
//

  result:rank 138 rating +56

AtCoder Grand Contest 034的更多相关文章

  1. Atcoder Grand Contest 034 F - RNG and XOR(FWT)

    Atcoder 题面传送门 & 洛谷题面传送门 tsc 考试前 A 的题了,结果到现在才写这篇题解--为了 2mol 我已经一周没碰键盘了,现在 2mol 结束算是可以短暂的春天 短暂地卷一会 ...

  2. AtCoder Grand Contest 012

    AtCoder Grand Contest 012 A - AtCoder Group Contest 翻译 有\(3n\)个人,每一个人有一个强大值(看我的假翻译),每三个人可以分成一组,一组的强大 ...

  3. AtCoder Grand Contest 011

    AtCoder Grand Contest 011 upd:这篇咕了好久,前面几题是三周以前写的... AtCoder Grand Contest 011 A - Airport Bus 翻译 有\( ...

  4. AtCoder Grand Contest 031 简要题解

    AtCoder Grand Contest 031 Atcoder A - Colorful Subsequence description 求\(s\)中本质不同子序列的个数模\(10^9+7\). ...

  5. AtCoder Grand Contest 010

    AtCoder Grand Contest 010 A - Addition 翻译 黑板上写了\(n\)个正整数,每次会擦去两个奇偶性相同的数,然后把他们的和写会到黑板上,问最终能否只剩下一个数. 题 ...

  6. AtCoder Grand Contest 009

    AtCoder Grand Contest 009 A - Multiple Array 翻译 见洛谷 题解 从后往前考虑. #include<iostream> #include< ...

  7. AtCoder Grand Contest 008

    AtCoder Grand Contest 008 A - Simple Calculator 翻译 有一个计算器,上面有一个显示按钮和两个其他的按钮.初始时,计算器上显示的数字是\(x\),现在想把 ...

  8. AtCoder Grand Contest 007

    AtCoder Grand Contest 007 A - Shik and Stone 翻译 见洛谷 题解 傻逼玩意 #include<cstdio> int n,m,tot;char ...

  9. AtCoder Grand Contest 006

    AtCoder Grand Contest 006 吐槽 这套题要改个名字,叫神仙结论题大赛 A - Prefix and Suffix 翻译 给定两个串,求满足前缀是\(S\),后缀是\(T\),并 ...

随机推荐

  1. idea 如何新建一个Maven项目并且写第一个servlet

    使用idea已经有段时间了,但是一直没有自己亲自新建一个项目,从头开始写一个Servlet,今天就来学习一下,并且记一个笔记. 一. 1.首先,打开idea new-->Project 2.选择 ...

  2. Sizes of integer types 整形字节长度 系统字节

    /usr/include/limits.h /* Copyright (C) 1991, 1992, 1996, 1997, 1998, 1999, 2000, 2005 Free Software ...

  3. 003 centos7中关闭防火墙

    在centos7中,防火墙有了新的变化.下面是常用的几个命令. 1.查看状态 systemctl status firewalld 2.关闭防火墙 systemctl stop firewalld.s ...

  4. Tomcat redis session manager connect redis show: ERR Client sent AUTH, but no password is set

    解决问题redis问题:ERR Client sent AUTH, but no password is set - 东篱煮酒 - 博客园https://www.cnblogs.com/niepeis ...

  5. 【转】暴力破解无线WiFi密码

    # coding:utf-8 import pywifi from pywifi import const import time from asyncio.tasks import sleep cl ...

  6. python中修改列表元素的方法

    一.在for循环中直接更改列表中元素的值不会起作用: 如: l = list(range(10)[::2]) print (l) for n in l: n = 0 print (l) 运行结果: [ ...

  7. 005-guava 集合-集合工具类-java.util.Collections中未包含的集合工具[Maps,Lists,Sets],Iterables、Multisets、Multimaps、Tables

    一.概述 工具类与特定集合接口的对应关系归纳如下: 集合接口 属于JDK还是Guava 对应的Guava工具类 Collection JDK Collections2:不要和java.util.Col ...

  8. C# WinForm获取 当前执行程序路径的几种方法(转)

    1.获取和设置当前目录的完全限定路径. string str = System.Environment.CurrentDirectory; Result: C:xxxxxx 2.获取启动了应用程序的可 ...

  9. deployment.yaml 带同步时区

    [root@lab2 dandang]# cat dandang.v1.yaml apiVersion: v1 kind: ReplicationController metadata: name: ...

  10. ecshop添加商品筛选功能

    ecshop商品属性一直是使用问题的难点,而“属性筛选”更是ecshop属性中的难点,那么下面来详细说明一下 属性筛选功能 第一,属性筛选的特点: 属性筛选必须是分类页才会显示,列出所有商品的唯一属性 ...