貌似洛谷的题面是没有翻译的

QWQ

大致题面是这个样子,但是可能根据题目本身有不同的地方

完全懵逼的一个题(果然博弈论就是不一样)

首先,我们考虑把题目转化成一个可做的模型。

我们分别从\(s\)和\(t\)跑两边全图最短路,这样,对于每个点,我们就能得到\(dis[i]\)和\(disn[i]\)。

这时候,我们把每个图上的点,看成一个平面上的点\((dis[i],disn[i])\),那么对于\(Alice\)来说,一次就相当于取若干行,\(Bob\)就是取若干列。然后两个人最大化分数差

不难发现,这个问题,我们可以通过离散化之后,就可以直接dp了

QWQ

(虽然dp部分更难想)

考虑到我们只知道起始状态,所以我们要尝试直接倒着\(dp\),令\(dp[i][j][0/1]\)表示当前是该\(Alice/Bob\)操作,然后还没有分配的区域是\((i+1,j+1)->(n,m)\)的最大分数差。

或者换种说法,

就是示\(覆盖了[x+1~n] 行,[y+1~m]列,当前取行/列的最大/最小差距\)

QWQ虽然感觉这个dp状态有点诡异

转移的时候,一次转移一行或者一列

对于当前的一个状态\(dp[i][j][0]\),我们需要\(check\)一下有没有第\(i+1\)i行有没有数(权值),如果没有,那么只能从\(dp[i+1][j][0]\)转移过来(这里可以理解为,如果没有数,那么一定是只能从上一个人那里转移过来),

不然就是\(max(dp[i+1][j][0],dp[i+1][j][1])+val\)(可以和上一次一样,或者单独拿了这个),令一状态也同理

for (int i=hang;i>=0;i--)
for (int j=line;j>=0;j--)
{
//if (i==line && j==line)
if (i!=hang)
{
int now = getnumx(i+1,j+1,line);
int ss = getsumx(i+1,j+1,line);
if (!now) dp[i][j][0]=dp[i+1][j][0];
else dp[i][j][0]=max(dp[i+1][j][0],dp[i+1][j][1])+ss;
}
if (j!=line)
{
int now = getnumy(j+1,i+1,hang);
int ss = getsumy(j+1,i+1,hang);
if (!now) dp[i][j][1]=dp[i][j+1][1];
else dp[i][j][1]=min(dp[i][j+1][0],dp[i][j+1][1])-ss;
}
}

官方题解我也放一下

下面是整个的代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk makr_pair
#define int long long
#define pa pair<long long,long long>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 2010;
const int maxm = 1e6+1e2;
int point[maxn],nxt[maxm],to[maxm];
int cnt,n,m;
int dis[maxn],vis[maxn];
int sumx[maxn][maxn],sumy[maxn][maxn];
int numx[maxn][maxn],numy[maxn][maxn];
int val[maxm];
int disn[maxn];
int cost[maxn];
int hang,line;
int s,t;
int sum[maxn][maxn];
int num[maxn][maxn];
int dp[maxn][maxn][2];
priority_queue<pa,vector<pa>,greater<pa> > q;
struct Node{
int x,y;
};
Node a[maxn];
vector<int> vx,vy;
void addedge(int x,int y,int w)
{
nxt[++cnt]=point[x];
to[cnt]=y;
val[cnt]=w;
point[x]=cnt;
}
void dijkstra(int s)
{
memset(vis,0,sizeof(vis));
memset(dis,127/3,sizeof(dis));
dis[s]=0;
q.push(make_pair(0,s));
while (!q.empty())
{
int x=q.top().second;
q.pop();
if (vis[x]) continue;
vis[x]=1;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (dis[p]>dis[x]+val[i])
{
dis[p]=dis[x]+val[i];
q.push(make_pair(dis[p],p));
}
}
}
}
void dijkstran(int s)
{
memset(vis,0,sizeof(vis));
memset(disn,127/3,sizeof(disn));
disn[s]=0;
q.push(make_pair(0,s));
while (!q.empty())
{
int x=q.top().second;
q.pop();
if (vis[x]) continue;
vis[x]=1;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (disn[p]>disn[x]+val[i])
{
disn[p]=disn[x]+val[i];
q.push(make_pair(disn[p],p));
}
}
}
}
//之所以倒着dp的原因是,因为我们只知道开始局面先手的情况,所以需要倒着来推
int getnumx(int x,int l,int r) {return numx[x][r]-numx[x][l-1];}
int getnumy(int y,int l,int r) {return numy[r][y]-numy[l-1][y];}
int getsumx(int x,int l,int r) {return sumx[x][r]-sumx[x][l-1];}
int getsumy(int y,int l,int r) {return sumy[r][y]-sumy[l-1][y];}
signed main()
{
n=read(),m=read();
s=read(),t=read();
int flag=0;
for (int i=1;i<=n;i++) cost[i]=read();
for (int i=1;i<=m;i++)
{
int x=read(),y=read(),w=read();
addedge(x,y,w);
addedge(y,x,w);
}
// flag=read();
dijkstra(s);
dijkstran(t);
// cout<<dis[3]<<" "<<disn[4]<<endl;
for (int i=1;i<=n;i++) vx.push_back(dis[i]),vy.push_back(disn[i]);
sort(vx.begin(),vx.end());
sort(vy.begin(),vy.end());
int hang = unique(vx.begin(),vx.end())-vx.begin();
int line = unique(vy.begin(),vy.end())-vy.begin();
vx.resize(hang);
vy.resize(line);
for (int i=1;i<=n;i++)
{
int x = lower_bound(vx.begin(),vx.end(),dis[i])-vx.begin()+1;
int y = lower_bound(vy.begin(),vy.end(),disn[i])-vy.begin()+1;
num[x][y]++;
sum[x][y]+=cost[i];
}
for (int i=1;i<=hang+1;i++)
for (int j=1;j<=line+1;j++)
sumx[i][j]=sumx[i][j-1]+sum[i][j],numx[i][j]=numx[i][j-1]+num[i][j];
for (int j=1;j<=line+1;j++)
for (int i=1;i<=hang+1;i++)
sumy[i][j]=sumy[i-1][j]+sum[i][j],numy[i][j]=numy[i-1][j]+num[i][j];
//这里具体的dp数组的含义就是这一次是该谁操作,然后剩下没有被占领的是从(i+1,j+1)到(n,m)这个子矩形的分数差
for (int i=hang;i>=0;i--)
for (int j=line;j>=0;j--)
{
//if (i==line && j==line)
if (i!=hang)
{
int now = getnumx(i+1,j+1,line);
int ss = getsumx(i+1,j+1,line);
if (!now) dp[i][j][0]=dp[i+1][j][0];
else dp[i][j][0]=max(dp[i+1][j][0],dp[i+1][j][1])+ss;
}
if (j!=line)
{
int now = getnumy(j+1,i+1,hang);
int ss = getsumy(j+1,i+1,hang);
if (!now) dp[i][j][1]=dp[i][j+1][1];
else dp[i][j][1]=min(dp[i][j+1][0],dp[i][j+1][1])-ss;
}
}
if(dp[0][0][0]>0) cout<<"Break a heart"<<"\n";
if(dp[0][0][0]<0) cout<<"Cry"<<"\n";
if (dp[0][0][0]==0) cout<<"Flowers"<<"\n";
return 0;
}

CF536D Tavas in Kansas(博弈论+dp)的更多相关文章

  1. [CF536D]Tavas in Kansas

    [CF536D]Tavas in Kansas 题目大意: 一张\(n(n\le2000)\)个点,\(m(m\le10^5)\)条边的无向带权连通图(权值可以为负).A.B两人分别在\(s,t\)点 ...

  2. Codeforces 536D - Tavas in Kansas(dp)

    Codeforces 题目传送门 & 洛谷题目传送门 其实这题本该 2019 年 12 月就 AC 的(详情请见 ycx 发此题题解的时间),然鹅鸽到了现在-- 首先以 \(s,t\) 分别为 ...

  3. 2018.09.25 poj2068 Nim(博弈论+dp)

    传送门 题意简述:m个石子,有两个队每队n个人循环取,每个人每次取石子有数量限制,取最后一块的输,问先手能否获胜. 博弈论+dp. 我们令f[i][j]f[i][j]f[i][j]表示当前第i个人取石 ...

  4. 【uoj#51】[UR #4]元旦三侠的游戏 博弈论+dp

    题目描述 给出 $n$ 和 $m$ ,$m$ 次询问.每次询问给出 $a$ 和 $b$ ,两人轮流选择:将 $a$ 加一或者将 $b$ 加一,但必须保证 $a^b\le n$ ,无法操作者输,问先手是 ...

  5. 【bzoj4550】小奇的博弈 博弈论+dp

    题目描述 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色.最左边是白色棋子,最右边 是黑色棋子,相邻的棋子颜色不同.   小奇可以移动白色棋子,提比可以移动黑色的棋子, ...

  6. 「模拟赛20181025」御风剑术 博弈论+DP简单优化

    题目描述 Yasuo 和Riven对一排\(n\)个假人开始练习.斩杀第\(i\)个假人会得到\(c_i\)个精粹.双方轮流出招,他们在练习中互相学习,所以他们的剑术越来越强.基于对方上一次斩杀的假人 ...

  7. BZOJ_2017_[Usaco2009 Nov]硬币游戏_博弈论+DP

    BZOJ_2017_[Usaco2009 Nov]硬币游戏_博弈论+DP Description 农夫约翰的奶牛喜欢玩硬币游戏,因此他发明了一种称为“Xoinc”的两人硬币游戏. 初始时,一个有N(5 ...

  8. 【CSA49F】【XSY3317】card 博弈论 DP

    题目大意 不会博弈论的 yww 在和博弈论大师 yxq 玩一个游戏. 有 \(n\) 种卡牌,第 \(i\) 种卡牌有 \(b_i\) 张. yww 会先把所有 \(B=\sum_{i=1}^nb_i ...

  9. 湖南大学第十四届ACM程序设计新生杯(重现赛)I:II play with GG(博弈论||DP)

    链接:https://ac.nowcoder.com/acm/contest/338/I 来源:牛客网 题目描述 IG won the S championship and many people a ...

随机推荐

  1. 高德地图——骑行路线&骑行指定

    &plugin=AMap.Riding 也是[]中放json, 包含keyword和city,不能有途经1.骑行路线(关键字) <!DOCTYPE html> <html&g ...

  2. 剑指 Offer 33. 二叉搜索树的后序遍历序列

    剑指 Offer 33. 二叉搜索树的后序遍历序列 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果.如果是则返回 true,否则返回 false.假设输入的数组的任意两个数字都互不相同. ...

  3. Python - 面向对象编程 - 新式类和旧式类

    object object 是 Python 为所有对象提供的父类,默认提供一些内置的属性.方法:可以使用 dir 方法查看 新式类 以 object 为父类的类,推荐使用 在 Python 3.x ...

  4. ArcEngine+C# 森林资源仿真系统 核心代码

    目录 第一章 基础功能的核心代码 实现滚轮缩放事件 创建或获取地理数据(导入前询问用户是否覆盖) 创建要素类(Shape) 点列数据创建要素类 Shape文件创建要素类 GDB中取出要素类 创建栅格数 ...

  5. 操作系统IO之零拷贝技术

    磁盘可以说是计算机系统最慢的硬件之一,读写速度相差内存 10 倍以上,所以针对优化磁盘的技术非常的多,比如零拷贝.直接 I/O.异步 I/O 等等,这些优化的目的就是为了提高系统的吞吐量,另外操作系统 ...

  6. JAVA安全基础之代理模式(二)

    JAVA安全基础之代理模式(二) 上篇讲到静态代理模式,这时候我们发现,一个代理类只能为一个类服务,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐.所以就有了动态代理 动态代理 动态代理的 ...

  7. vuex前端工程化之动态导入文件--require.context( )

    随着项目的复杂,文件结构越来越多,Store中modules中的文件也越来越多,如果一个一个加载是不是很麻烦呢? 先看一个项目中store项目结构: 过去都是通过import分别引入文件: 1 imp ...

  8. 【分布式微服务企业快速架构】SpringCloud分布式、微服务、云架构快速开发平台源码

    鸿鹄云架构[系统管理平台]是一个大型 企业.分布式.微服务.云架构的JavaEE体系快速研发平台,基于 模块化.微服务化.原子化.热部署的设计思想,使用成熟领先的无商业限制的主流开源技术 (Sprin ...

  9. 【第十四篇】- Maven 自动化构建之Spring Cloud直播商城 b2b2c电子商务技术总结

    Maven 自动化构建 自动化构建定义了这样一种场景: 在一个项目成功构建完成后,其相关的依赖工程即开始构建,这样可以保证其依赖项目的稳定. 比如一个团队正在开发一个项目 bus-core-api, ...

  10. PHP打印跟踪调试信息

    对于大部分编译型语言来说,比如 C . Java . C# ,我们都能很方便地进行断点调试,但是 PHP 则必须安装 XDebug 并且在编辑器中进行复杂的配置才能实现断点调试的能力.不过,如果只是简 ...