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. JS数组常见方法的深浅拷贝分类

    一.涉及浅拷贝类方法,会改变原数组 1,pop():   删除 arrayObject 的最后一个元素,把数组长度减 1,并且返回它删除的元素的值.如果数组已经为空,则 pop() 不 改变数组,并返 ...

  2. Android页面切换

    参考地址: http://www.crifan.com/android_how_to_create_new_ui_and_switch_to_another_new_ui/ 想要实现,在Android ...

  3. ffmpeg编译错误,提示找不到相应的shared libraries :libavdevice.so.53

    解决方法:需要配置响应的环境变量,以便能找到响应的lib库 vi   /etc/ld.so.conf 加入   /usr/local/lib 执行  sudo  ldconfig

  4. iptables 配置场景3

    iptables -I INPUT -i lo -j ACCEPT    #允许本地回环地址访问: iptables -I INPUT -m state --state ESTABLISHED,REL ...

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

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

  6. tengine无法解析ssi报错 Nginx: unsafe URI detected while sending response

    Nginx: unsafe URI detected while sending response 现象:# 类似 <!--#include virtual="../library/h ...

  7. OMPL RRTConnet 生成路径和可视化

    默认规划路径算法和RRTConnet路径规划算法生成路径 1.  源代码 #include <ompl/base/SpaceInformation.h> #include <ompl ...

  8. matlab基本函数strcmp num2str 字符串格式

    一起来学演化计算-matlab基本函数strcmp num2str 字符串格式 觉得有用的话,欢迎一起讨论相互学习~Follow Me strcmp 比较字符串 语法 tf = strcmp(s1,s ...

  9. Django model中的save后的return

    先给结论吧:在Django model的操作函数中,obj.save()后再执行return obj会返回obj的ID. 看例子: ... def create_session(self,bind_h ...

  10. 增强篇3 SAP表字段增强

    有两种方式:  Include  和 Append 1.INCLUDE一般都是标准预留的增强: 以CO01生产订单增强字段为例 在表AUFK中INCLUDE的结构“CI_AUFK”加入自定义字段 保存 ...