BZOJ1124 POI2008枪战Maf(环套树+贪心)
每个点出度都为1,可以发现这张图其实是个环套树森林,树中儿子指向父亲,环上边同向。
首先自环肯定是没救的,先抬出去。
要使死亡人数最多的话,显然若一个点入度为0其不会死亡,而一个孤立的环至少会留下一个点。对于环套树,若某个点有子树,可以以瞄准它的点为起点,每个点都被在环上瞄准他的点所击中。这样就剩下了很多棵树,除叶子节点的点都会死亡。
死亡人数最少似乎同样可以贪心,虽然我没这么写。可以发现最后存活下来的人之间一定不存在瞄准关系,否则必有一个死亡。并且只要最后存活下来的人之间不存在瞄准关系(且不被瞄准的存活),一定有方案使这些人最终存活下来,对于一个连通块人的死亡只要按照拓扑逆序开枪即可(使孤立环全部死亡是办不到的,但显然要使死亡人数最少我们不会这样干)。于是求一下环套树的包含所有叶子节点的最大独立集即可。
细节挺多,在luoguA了,bzoj跑了好长时间之后wa掉了,不知道哪写挂了啊。
upd:发现是一些奇怪的地方爆了int……现在A掉辣!
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 1000010
int n,a[N],id[N],degree[N],dfn[N],low[N],stk[N],set[N],size[N];
int top=,cnt=,t=;
long long ans1=,ans2=,f[N][],g[N][][];
bool flag[N],isroot[N];
int p[N];
struct data{int to,nxt;
}edge[N];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void tarjan(int k)
{
dfn[k]=low[k]=++cnt;
stk[++top]=k;flag[k]=;
if (a[a[k]]!=a[k])
if (!dfn[a[k]]) tarjan(a[k]),low[k]=min(low[k],low[a[k]]);
else if (flag[a[k]]) low[k]=min(low[k],dfn[a[k]]);
if (dfn[k]==low[k])
{
t++;
while (stk[top]!=k)
{
set[stk[top]]=t;
size[t]++;
flag[stk[top]]=;
top--;
}
set[k]=t;size[t]++;flag[k]=;top--;
}
}
void dfs(int k)
{
f[k][]=,f[k][]=;
if (!degree[k]) f[k][]=-n;
for (int i=p[k];i;i=edge[i].nxt)
if (size[set[edge[i].to]]==)
{
dfs(edge[i].to);
f[k][]+=max(f[edge[i].to][],f[edge[i].to][]);
f[k][]+=f[edge[i].to][];
}
}
int main()
{
n=read();
for (int i=;i<=n;i++)
{
a[i]=read();
if (a[i]==i) ans1++;
else degree[a[i]]++;
}
for (int i=;i<=n;i++)
if (!dfn[i]&&a[i]!=i) tarjan(i);
for (int i=;i<=n;i++)
if (degree[i]&&size[set[i]]==) ans1++;
memset(flag,,sizeof(flag));
for (int i=;i<=n;i++)
if (size[set[i]]>&°ree[i]>) flag[set[i]]=;
for (int i=;i<=t;i++)
if (size[i]>) ans1+=size[i]-+flag[i];
t=;
for (int i=;i<=n;i++)
if (a[i]!=i) addedge(a[i],i);
for (int i=;i<=n;i++)
if (size[set[i]]>||a[a[i]]==a[i]&&a[i]!=i) isroot[i]=;
for (int i=;i<=n;i++)
if (isroot[i]) dfs(i);
memset(dfn,,sizeof(dfn));
for (int i=;i<=n;i++)
if (isroot[i]&&!dfn[i])
if (a[a[i]]==a[i]) ans2+=max(f[i][],f[i][]);
else
{
int x=i,t=;
while (a[x]!=i) dfn[x=a[x]]=,id[++t]=x;
id[++t]=i;dfn[i]=;
for (int j=;j<=t;j++) g[i][][]=g[i][][]=g[i][][]=g[i][][]=;
g[][][]=f[id[]][],g[][][]=f[id[]][];
g[][][]=g[][][]=-n;
for (int j=;j<=t;j++)
{
g[j][][]=max(g[j-][][],g[j-][][])+f[id[j]][];
g[j][][]=max(g[j-][][],g[j-][][])+f[id[j]][];
g[j][][]=g[j-][][]+f[id[j]][];
g[j][][]=g[j-][][]+f[id[j]][];
}
ans2+=max(g[t][][],max(g[t][][],g[t][][]));
}
ans2=n-ans2;
cout<<ans2<<' '<<ans1;
return ;
}
BZOJ1124 POI2008枪战Maf(环套树+贪心)的更多相关文章
- BZOJ1124 [POI2008]枪战Maf[贪心(证明未完成)+拓扑排序]
吐槽:扣了几个小时,大致思路是有了,但是贪心的证明就是不会, 死磕了很长时间,不想想了,结果码代码又不会码.. 深深体会到自己码力很差,写很多行还没写对,最后别人代码全一二十行,要哭了 以下可能是个人 ...
- bzoj1124[POI2008]枪战maf
这代码快写死我了.....死人最多随便推推结论.死人最少,每个环可以单独考虑,每个环上挂着的每棵树也可以分别考虑.tarjan找出所有环,对环上每个点,求出选它和不选它时以它为根的树的最大独立集(就是 ...
- BZOJ 1124: [POI2008]枪战Maf(构造 + 贪心)
题意 有 \(n\) 个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪. 因此,对于不同的开枪顺序,最后死的人也不同. 问最 ...
- 【BZOJ 1124】[POI2008] 枪战Maf Tarjan+树dp
#define int long long using namespace std; signed main(){ 这个题一看就是图论题,然后我们观察他的性质,因为一个图论题如果没有什么性质,就是真· ...
- 【BZOJ1124】[POI2008]枪战Maf 贪心+思路题
[BZOJ1124][POI2008]枪战Maf Description 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开 ...
- bzoj 1124 [POI2008]枪战Maf 贪心
[POI2008]枪战Maf Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 741 Solved: 295[Submit][Status][Disc ...
- BZOJ 1124: [POI2008]枪战Maf
1124: [POI2008]枪战Maf Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 617 Solved: 236[Submit][Status ...
- [POI2008]枪战Maf题解
问题 C: [POI2008]枪战Maf 时间限制: 1 Sec 内存限制: 256 MB 题目描述 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺 ...
- [POI2008]枪战Maf
[POI2008]枪战Maf 题目 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的 ...
随机推荐
- linux下的C语言程序设计
Linux程序设计基础知识 Linux下C语言编程环境概述 Linux下C语言编程常用的编辑器是vim或emacs,编译器一般用gcc,编译链接程序用make,跟踪调试一般使用gdb,项目管理用mak ...
- CSV文件解析
CSV(逗号分隔值文件格式) 逗号分隔值(Comma-Separated Values,CSV,有时也称为字符分隔值,因为分隔字符也可以不是逗号),其文件以纯文本形式存储表格数据(数字和 ...
- 在VS2017上使用C#调用非托管C++生成的DLL文件(图文讲解)
原文:在VS2010上使用C#调用非托管C++生成的DLL文件(图文讲解) 背景 在项目过程中,有时候你需要调用非C#编写的DLL文件,尤其在使用一些第三方通讯组件的时候,通过C#来开发应用软件时,就 ...
- [Oacle][Partition]Partition操作与 Index, Global Index 的关系
[Oacle][Partition]Partition操作与 Index, Global Index 的关系: ■ Regarding the local index and the global i ...
- 2018年高教社杯全国大学生数学建模竞赛B题解题思路
题目 先贴下B题的题目吧 问题B 智能RGV的动态调度策略 图1是一个智能加工系统的示意图,由8台计算机数控机床(Computer Number Controller,CNC).1辆轨道式自动引 ...
- Ionic2 下处理 Android 设备下返回按钮的事件
原文发表于我的技术博客 本文分享了 Ionic2 下处理 Android 设备下返回按钮的事件,供参考. 原文发表于我的技术博客 代码中我分享了如何捕捉 Ionic2 项目在 Android 设备下返 ...
- 运维中的日志切割操作梳理(Logrotate/python/shell脚本实现)
对于Linux系统安全来说,日志文件是极其重要的工具.不知为何,我发现很多运维同学的服务器上都运行着一些诸如每天切分Nginx日志之类的CRON脚本,大家似乎遗忘了Logrotate,争相发明自己的轮 ...
- mysql操作命令梳理(2)-alter(update、insert)
在mysql运维操作中会经常使用到alter这个修改表的命令,alter tables允许修改一个现有表的结构,比如增加或删除列.创造或消去索引.改变现有列的类型.或重新命名列或表本身,也能改变表的注 ...
- 如何解决jersey框架中以json格式返回数组,当数组中元素一个时json格式不对
原文地址:http://www.cnblogs.com/swpk/p/3566536.html?utm_source=tuicool jersey 是oracle 出的一个较好的REST框架.使用此框 ...
- Java开发23种设计模式之禅
六大原则 23种设计模式: 总体来说设计模式分为三大类: *创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. *结构型模式,共七种:适配器模式.装饰器模式.代理模式.外 ...