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个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的 ...
随机推荐
- Literal 字面值 字面量 的理解
Literal 字面值 字面量 Literal, 在程序语言中,指表示某种数据值的符码.如,123 是整数值符码, 3.14 是浮点值符码,abcd 是字串值符码,True, False, 是逻辑值符 ...
- LOJ558 我们的 CPU 遭到攻击 LCT
传送门 题意:写一个数据结构,支持森林上:连边.删边.翻转点的颜色(黑白).查询以某一点为根的某棵树上所有黑色点到根的距离和.$\text{点数} \leq 10^5 , \text{操作数} \le ...
- Luogu P2312 解方程
据大佬的说法这种大力乱搞题出在除NOIp以外的任何比赛都是很好的然而就是被出在了NOIp 首先对于想直接上高精的同学,我还是祝你好运吧. 我们考虑一个十分显然的性质,若\(a=b\),则对于任一自然数 ...
- 【php增删改查实例】第二十三节 - PHP文件上传
22. PHP文件上传 22.1 资源文件 将这三个东西拷贝项目的根目录. 拷贝完毕后,打开upload.html: 现在,我们在项目的根目录去编写一个upload.php. PHP给我们提供了很多关 ...
- 开发CMDB系统
背景: 在现网环境中服务器多了每天服务器的配置 情况我们很难记住,当某台服务器硬件配置变化后可以第一时间了解,某台服务器出现问题时可以快速定位机架位置,之前都是excel文档,要查某项数据时极不方便. ...
- 阿里云Https通配符证书购买
先付款,再绑定证书. 会款后会审核,等待... DNS解析配置错误 按域名授权配置,增加一条 DNS Txt记录值.
- sql 某字段存储另一个表的多个id值并以逗号分隔,现根据id去中文并拼接同样以逗号分隔
首先介绍用到的两个函数 charindex(要查找的表达式1,表达式2),返回值为表达式1在表达式2中的下标,未找到则返回0.(sql的下标是从1开始的),例如 select charindex('s ...
- Visual Studio 2015的安装及单元测试练习
第一部分:Visual Studio 2015的安装 我电脑系统是win10,所以安装的是Visual Studio 2015,安装步骤部分截图如图所示: 1.安装类型选项界面:可以选择默认安装,可以 ...
- SCRUM 12.22
周一,大家现在课程也比较少,今天都在非常努力地写代码. 任务分配如往常一样,我们现在基本将工作的重心放在完善已有的组件上. 成员 任务 彭林江 落实API 牛强 落实意见反馈功能测试 高雅智 测试已完 ...
- linux内实践核分析模块