Codeforces 题目传送门 & 洛谷题目传送门

其实这题本该 2019 年 12 月就 AC 的(详情请见 ycx 发此题题解的时间),然鹅鸽到了现在……

首先以 \(s,t\) 分别为源点跑两遍 dijkstra 是不可避免的,求出 \(s,t\) 到每个点的最短距离 \(d1_i,d2_i\)

其次还可以发现一件事情,那就是对于 \(\forall i,j\),若 \(d1_i<d1_j\) 并且 \(j\) 被选择了,那么 \(i\) 一定被选择了,对于 \(d2_i\) 也可得到类似的性质。换句话说,对于游戏任意一种局面,\(\exist x,y\) 使得恰好只剩下 \(d1_i\geq x\) 且 \(d2_i\geq y\) 的 \(i\) 没有被选择。故考虑以此为状态设计 dp

将 \(d1,d2\) 离散化。设 \(dp_{p,x,y}\) 表示此时轮到 \(p\)(\(0\) 表示先手,\(1\) 表示后手),还剩下 \(d1_i\geq x\) 且 \(d2_i\geq y\) 的点没有被选择,所能得到的最大得分。状态转移方程很容易得到,以 \(p=0\) 为例,显然这一步操作之后留下来的应当是 \(d1_i\geq z\) 且 \(d2_i\geq y\) 的城市,其中 \(z\) 为某个大于 \(x\) 的数,我们不妨枚举 \(z\),记 \(c_{x,y}\) 为 \(d1_i\geq x\) 且 \(d2_i\ge y\) 的城市个数,\(s_{x,y}\) 为 \(d1_i\geq x\) 且 \(d2_i\ge y\) 的城市的权值之和,由于先手要多占领一些城市,故 \(c_{z,y}>c_{x,y}\),故我们有状态转移方程 \(dp_{0,x,y}=s_{x,y}-\min\limits_{c_{z,y}>c_{x,y}}dp_{1,z,y}\),\(dp_{1,x,y}\) 也同理。

容易发现对于某个 \(dp_{p,x,y}\),其决策的集合是一段后缀,故可以预处理 \(nt1_{i,j}\) 表示第一个满足 \(c_{k,j}>c_{i,j}\) 的 \(k\),\(nt2_{i,j}\) 表示 \(c_{i,l}>c_{i,j}\) 的 \(l\),这个预处理复杂度显然是 \(n^2\) 的,处理完之后就可以利用后缀 \(\min\) 进行 \(\mathcal O(1)\) 转移了。

最终先手得分的最大值即为 \(dp_{0,0,0}\),后手得分即为 \(s_{0,0}-dp_{0,0,0}\),比较二者大小即可。

时间复杂度 \(n^2\)。总之此题算 D1D 中较简单的了。

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
const int MAXN=2e3;
const int MAXM=1e5;
int n,m,s,t,p[MAXN+5],to[MAXM*2+5],nxt[MAXM*2+5],cst[MAXM*2+5],hd[MAXN+5],ec=0;
void adde(int u,int v,int w){to[++ec]=v;cst[ec]=w;nxt[ec]=hd[u];hd[u]=ec;}
ll d1[MAXN+5],d2[MAXN+5],key1[MAXN+5],key2[MAXN+5],uni1[MAXN+5],uni2[MAXN+5];
int c1[MAXN+5],c2[MAXN+5],num1=0,num2=0,cnt[MAXN+5][MAXN+5];ll sum[MAXN+5][MAXN+5];
ll dp[2][MAXN+5][MAXN+5],mn[2][MAXN+5][MAXN+5];
int nt1[MAXN+5][MAXN+5],nt2[MAXN+5][MAXN+5];
int main(){
scanf("%d%d%d%d",&n,&m,&s,&t);
for(int i=1;i<=n;i++) scanf("%d",&p[i]);
for(int i=1,u,v,w;i<=m;i++){scanf("%d%d%d",&u,&v,&w);adde(u,v,w);adde(v,u,w);}
priority_queue<pair<ll,int>,vector<pair<ll,int> >,greater<pair<ll,int> > > q;
memset(d1,63,sizeof(d1));d1[s]=0;q.push(mp(0,s));
while(!q.empty()){
pii pr=q.top();q.pop();int x=pr.se;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=cst[e];
if(d1[y]>d1[x]+z){
d1[y]=d1[x]+z;
q.push(mp(d1[y],y));
}
}
}
memset(d2,63,sizeof(d2));d2[t]=0;q.push(mp(0,t));
while(!q.empty()){
pii pr=q.top();q.pop();int x=pr.se;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=cst[e];
if(d2[y]>d2[x]+z){
d2[y]=d2[x]+z;
q.push(mp(d2[y],y));
}
}
}
for(int i=1;i<=n;i++) key1[i]=d1[i],key2[i]=d2[i];
sort(key1+1,key1+n+1);sort(key2+1,key2+n+1);key1[0]=key2[0]=-1;
for(int i=1;i<=n;i++){
if(key1[i]!=key1[i-1]) uni1[++num1]=key1[i];
if(key2[i]!=key2[i-1]) uni2[++num2]=key2[i];
}
for(int i=1;i<=n;i++) c1[i]=lower_bound(uni1+1,uni1+num1+1,d1[i])-uni1;
for(int i=1;i<=n;i++) c2[i]=lower_bound(uni2+1,uni2+num2+1,d2[i])-uni2;
// for(int i=1;i<=n;i++) printf("%d %d\n",c1[i],c2[i]);
for(int i=1;i<=n;i++) cnt[c1[i]][c2[i]]++,sum[c1[i]][c2[i]]+=p[i];
for(int i=num1;i;i--) for(int j=num2;j;j--){
cnt[i][j]+=cnt[i+1][j]+cnt[i][j+1]-cnt[i+1][j+1];
sum[i][j]+=sum[i+1][j]+sum[i][j+1]-sum[i+1][j+1];
}
// for(int i=1;i<=num1;i++) for(int j=1;j<=num2;j++)
// printf("%d %d %lld %lld\n",i,j,cnt[i][j],sum[i][j]);
for(int i=num1;i;i--) for(int j=num2;j;j--){
nt1[i][j]=(cnt[i][j]==cnt[i+1][j])?nt1[i+1][j]:(i+1);
nt2[i][j]=(cnt[i][j]==cnt[i][j+1])?nt2[i][j+1]:(j+1);
}
for(int i=num1;i;i--) for(int j=num2;j;j--){
if(!cnt[i][j]) continue;
dp[0][i][j]=sum[i][j]-mn[1][nt1[i][j]][j];
dp[1][i][j]=sum[i][j]-mn[0][i][nt2[i][j]];
// printf("%d %d %d %d\n",i,j,dp[0][i][j],dp[1][i][j]);
mn[0][i][j]=min(mn[0][i][j+1],dp[0][i][j]);
mn[1][i][j]=min(mn[1][i+1][j],dp[1][i][j]);
} ll sgn=sum[1][1]-(dp[0][1][1]<<1);
// printf("%d\n",dp[0][1][1]);
printf("%s\n",(sgn>0)?"Cry":((!sgn)?"Flowers":"Break a heart"));
return 0;
}

Codeforces 536D - Tavas in Kansas(dp)的更多相关文章

  1. CodeForces - 710E Generate a String (dp)

    题意:构造一个由a组成的串,如果插入或删除一个a,花费时间x,如果使当前串长度加倍,花费时间y,问要构造一个长度为n的串,最少花费多长时间. 分析:dp[i]---构造长度为i的串需要花费的最短时间. ...

  2. Educational Codeforces Round 51 D. Bicolorings(dp)

    https://codeforces.com/contest/1051/problem/D 题意 一个2*n的矩阵,你可以用黑白格子去填充他,求联通块数目等于k的方案数,答案%998244353. 思 ...

  3. CodeForces 536D Tavas in Kansas

    洛谷题目页面传送门 & CodeForces题目页面传送门 A和B在一张无向连通图\(G=(V,E),|V|=n,|E|=m\)上玩一个游戏,节点\(i\)有一个权值\(v_i\).A.B分别 ...

  4. Codeforces 295D - Greg and Caves(dp)

    题意: 给出一个 \(n \times m\) 的矩阵,需对其进行黑白染色,使得以下条件成立: 存在区间 \([l,r]\)(\(1\leq l\leq r\leq n\)),使得第 \(l,l+1, ...

  5. Codeforces 467C George and Job(DP)

    题目 Source http://codeforces.com/contest/467/problem/C Description The new ITone 6 has been released ...

  6. Codeforces A ACM (ACronym Maker) (dp)

    http://codeforces.com/gym/100650 概要:给出一个缩写,和一些单词,从单词中按顺序选一些字母作为缩写,问方案数. 限制:某些单词要忽略,每个单词至少要选一个字母. dp[ ...

  7. codeforces 813 D. Two Melodies(dp)

    题目链接:http://codeforces.com/contest/813/problem/D 题意:求两个不相交的子集长度之和最大是多少,能放入同一子集的条件是首先顺序不能变,然后每一个相邻的要么 ...

  8. codeforces 762 D. Maximum path(dp)

    题目链接:http://codeforces.com/problemset/problem/762/D 题意:给出一个3*n的矩阵然后问从左上角到右下角最大权值是多少,而且每一个点可以走上下左右,但是 ...

  9. CodeForces - 446A DZY Loves Sequences(dp)

    题意:给定一个序列a,求最长的连续子序列b的长度,在至多修改b内一个数字(可修改为任何数字)的条件下,使得b严格递增. 分析: 1.因为至多修改一个数字,假设修改a[i], 2.若能使a[i] < ...

随机推荐

  1. netty系列之:netty对http2消息的封装

    目录 简介 http2消息的结构 netty对http2的封装 Http2Stream Http2Frame 总结 简介 无论是什么协议,如果要真正被使用的话,需要将该协议转换成为对应的语言才好真正的 ...

  2. C/C++ 数据类型 表示最大 最小数值 探讨

    C/C++中存储数字格式有整型和浮点型 字符型数据本质上也是以整型存储 整型 对于整型数据,最大值最小值很好计算 先确定对应数据型在本地所占用的字节数,同一数据型由于系统或者编译器的不同,所占字节不同 ...

  3. Coursera Deep Learning笔记 序列模型(二)NLP & Word Embeddings(自然语言处理与词嵌入)

    参考 1. Word Representation 之前介绍用词汇表表示单词,使用one-hot 向量表示词,缺点:它使每个词孤立起来,使得算法对相关词的泛化能力不强. 从上图可以看出相似的单词分布距 ...

  4. Java:NIO 学习笔记-3

    Java:NIO 学习笔记-3 根据 黑马程序员 的课程 JAVA通信架构I/O模式,做了相应的笔记 3. JAVA NIO 深入剖析 在讲解利用 NIO 实现通信架构之前,我们需要先来了解一下 NI ...

  5. Git: 搭建一个本地私人仓库

    Git: 搭建一个本地私人仓库 寝室放个电脑.实验室也有个电脑 为进行数据同步,充分利用实验室的服务器搭建了个本地私人仓库 1. 安装流程 当然首先保证服务器上与PC机上都已经安装了可用的Git 在P ...

  6. BUAA-软件工程-个人总结与心得

    提问回顾以及个人总结 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 提问回顾与个人总结 我在这个课程的目标是 学习软件开发的过程,团队之间的写作 ...

  7. 大闸蟹的 O O 战记

    一. 第四单元架构设计分析 第一次作业,UML类图 第一次作业的主要任务是完成对UML类图的解析并实现查询等操作,需要在课程组给定的框架中添加函数.对于UML类图,其存储是按照元素来存储的,其将所有的 ...

  8. poi实现生成下拉选联动

    在我们实际的程序开发中,经常需要用到从excel导入数据中系统中,而为了防止用户在excel中乱输入文字,有些需要用到下拉选的地方,就需要从程序中动态生成模板.本例子简单的讲解一下,如何生成级联下拉选 ...

  9. 21.7.1 test

    \(NOI\) 模拟赛 呜呜呜 \(\cdots\cdots\) \(T1\) 类似哈夫曼编码,虽然没学过但是我依然画出了二叉树,然后尝试树形dp,并且最后还抓住了一个优化!让我兴奋地以为自己能赛时A ...

  10. C++ map操作——插入、查找、遍历

    c++ map 操作学习 #include <iostream> #include <map> #include <string> #include <vec ...