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. JVM 初始化阶段的重要意义分析

    1.创建一个Mytest6类和Singleton类 public class MyTest6 { public static void main(String[] args) { Singleton ...

  2. graph embedding 使用方法

    无论是network embedding 还是graph embedding都是通过节点(node)和边的图,学出每个节点的embedding向量. 比较流行的算法有: Model Paper Not ...

  3. 【Java.Regex】用正则表达式查找Java文件里的字符串

    代码: import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; imp ...

  4. Windows 开始 运行中所打开的默认程序以及优先级

    Windows 开始 运行中所打开的默认程序以及优先级 Default app/softwares and priority for Windows/start/run 商务合作,科技咨询,版权转让: ...

  5. vue子组件数据变化同步到父组件中

    方法:通过watch监听子组件数据变化 1.父组件中注册方法 <Child @getChildValue="getChildValue"></Child> ...

  6. 新概念英语第二册Lesson5:No wrong numbers

    Lesson 5 No wrong numbers 无错号之虞 First listen and then answer the question. 听录音,然后回答以下问题. What does ' ...

  7. 在linux的用户空间操作gpio

    1. 使能linux内核选项CONFIG_GPIO_SYSFS CONFIG_GPIO_SYSFS=y 2. 测试方法 2.1 关注/sys/class/gpio下的文件 --export/unexp ...

  8. typeScript模块<二>

    /*模块 1 模块的的概念 2 模块导出的几种方法 1.export 导出声明 2.export 导出语句 3.export default 4.import导入模块 3 模块化封装上一讲的DB库 * ...

  9. openresty开发系列1--网关API架构及选型

    微服务架构在项目中的应用越来越多,我们知道在微服务架构风格中,一个大应用被拆分成为了多个小的服务系统提供出来,这些小的系统他们可以自成体系,也就是说这些小系统可以拥有自己的数据库,框架甚至语言等,这些 ...

  10. ROS学习笔记(一)

    运行ROS例程(turtlesim)1)安装turtlesim包sudo apt-get install ros-kinetic-turtlesim2)运行管理器节点roscore3)运行turtle ...