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. nssm.exe使用方法

    nssm no-sucking service manager 1. 安装服务命令 nssm install <servicename> nssm install <servicen ...

  2. Java:并发笔记-07

    Java:并发笔记-07 说明:这是看了 bilibili 上 黑马程序员 的课程 java并发编程 后做的笔记 6. 共享模型之不可变 本章内容 不可变类的使用 不可变类设计 无状态类设计 6.1 ...

  3. mybatis学习笔记(2)基本原理

    引言在mybatis的基础知识中我们已经可以对mybatis的工作方式窥斑见豹(参考:<MyBatis----基础知识>).但是,为什么还要要学习mybatis的工作原理?因为,随着myb ...

  4. MIPI归纳---为什么阻抗为100欧姆

    根据LVDS(Low Voltage Differential Signaling)电平定义的. LVDS差分信号PN两线最大幅度是350mV,内部一个恒流源电流是3.5mA.于是终端匹配电阻是100 ...

  5. [CSP-S2021] 回文

    链接: P7915 题意: 给出一个长度为 \(2n\) 的序列 \(a\),其中 \(1\sim n\) 每个数出现了 2 次.有 L,R 两种操作分别是将 \(a\) 的开头或末尾元素加入到初始为 ...

  6. Python中根据时间自动创建文件夹

    导语 ​ 电脑桌面文件太多查找起来比较花费时间,并且凌乱的电脑桌面也会影响工作心情,于是利用python根据时间自动建立当日文件夹,这样就可以把桌面上文件按时间进行存放. 代码实现 # _*_codi ...

  7. 如何优雅的处理 accept 出现 EMFILE 的问题

    通常情况下,服务端调用 accept 函数会返回一个新的文件描述符,用于和客户端之间的数据传输 在服务器的开发中,有时会遇到这种情况:当调用 accept 函数接受客户端连接,函数返回失败,对应的错误 ...

  8. iptables 原理及应用

    转自:iptables 原理及应用 iptables是一个Linux下优秀的nat+防火墙工具,我使用该工具以较低配置的传统pc配置了一个灵活强劲的防火墙+nat系统,小有心得,看了网上也有很多这方面 ...

  9. 『学了就忘』Linux基础 — 16、Linux系统与Windows系统的不同

    目录 1.Linux严格区分大小写 2.Linux一切皆文件 3.Linux不靠扩展名区分文件类型 4.Linux中所有的存储设备都必须在挂载之后才能使用 5.Windows下的程序不能直接在Linu ...

  10. 王爽汇编第十章,call和ret指令

    目录 王爽汇编第十章,call和ret指令 call和ret指令概述: ret和retf ret指令 retf指令 call 和 ret 的配合使用 call指令详解 call原理 call指令所有写 ...