1124: [POI2008]枪战Maf

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 617  Solved: 236
[Submit][Status][Discuss]

Description

有n个人,每个人手里有一把手枪。一开始所有人都选定一个人瞄准(有可能瞄准自己)。然后他们按某个顺序开枪,且任意时刻只有一个人开枪。因此,对于不同的开枪顺序,最后死的人也不同。

Input

输入n人数<1000000 每个人的aim

Output

你要求最后死亡数目的最小和最大可能

Sample Input

8
2 3 2 2 6 7 8 5

Sample Output

3 5

HINT

 

Source

 

[Submit][Status][Discuss]

分析

很有意思的一道贪心题目,主要是代码实现上的细节挺多,要不就是今晚太困了……

两个问题要分开分析,有不同的贪心思路。

首先,枪杀关系类似于有向图。按照联通块进行划分,其可以分为大致三种情况——

  1. 单独一个点形成的自环。显然这个点必定会死,不论是最多死亡人数还是最少死亡人数,都会使答案+1。

  2. 一条链,最后的一个点可能是个自环,类似于1->2->3->4->5->5。显然这条链上除了1,其他点通过合理的顺序都可以被枪杀,所以最多死亡人数是len-1。因为1不会死,我们贪心的让1先杀死2,这样3就可以活下来;因为3可以活下来,所以贪心的杀死4,这样5就可以活下来。依次类推,得到一个贪心思路——如果当前认为一个点可以活,则贪心的杀死他的枪杀目标,给他枪杀目标的目标以更大的生存机会。如果这样发现,其枪杀目标的目标已经没有入边,则认为其也是可以活下来的,继续这一过程。

  3. 最为复杂的是基环内向树和简单的有向环。如果是环,那么至少要有一个点活着,最多只能有(size/2)个点活着。而如果是基环树,至少每条链的尾端要活着,至多可以做到类似于上面的贪心。

代码

 #include <bits/stdc++.h>
using namespace std; #define N 1000100 int n, to[N], ans1, ans2; namespace query1
{
int cnt[N];
int vis[N];
int que[N]; void solve(void)
{
ans1 = n; memset(cnt, , sizeof(cnt));
memset(vis, , sizeof(vis)); for (int i = ; i <= n; ++i)
++cnt[to[i]]; for (int i = ; i <= n; ++i)
if (i == to[i])
--cnt[i], vis[i] = ; int head = , tail = ; for (int i = ; i <= n; ++i)
if (!vis[i] && !cnt[i])
que[tail++] = i; while (head != tail)
{
int top = que[head++]; vis[top] = ; --ans1; if (!vis[to[top]])
{
vis[to[top]] = ; if (!vis[to[to[top]]] && --cnt[to[to[top]]] == )
que[tail++] = to[to[top]];
}
} for (int i = ; i <= n; ++i)
if (!vis[i])
{
int siz = ; for (int j = i; !vis[j]; j = to[j])
vis[j] = , ++siz; ans1 -= (siz >> );
}
}
} namespace query2
{
int cnt[N];
int vis[N];
int que[N];
int flg[N]; void solve(void)
{
ans2 = n; memset(cnt, , sizeof(cnt));
memset(vis, , sizeof(vis));
memset(flg, , sizeof(flg)); for (int i = ; i <= n; ++i)
++cnt[to[i]]; for (int i = ; i <= n; ++i)
if (i == to[i])
--cnt[i], vis[i] = ; int head = , tail = ; for (int i = ; i <= n; ++i)
if (!vis[i] && !cnt[i])
que[tail++] = i, --ans2; while (head != tail)
{
int top = que[head++]; flg[to[top]] = vis[top] = ; if (--cnt[to[top]] == )
que[tail++] = to[top];
} for (int i = ; i <= n; ++i)
if (!vis[i])
{
int flag = ; for (int j = i; !vis[j]; j = to[j])
vis[j] = , flag |= flg[j]; if (!flag)--ans2;
}
}
} signed main(void)
{
scanf("%d", &n); for (int i = ; i <= n; ++i)
scanf("%d", to + i); query1::solve();
query2::solve(); printf("%d %d\n", ans1, ans2);
}

BZOJ_1124.cpp

@Author: YouSiki

BZOJ 1124: [POI2008]枪战Maf的更多相关文章

  1. bzoj 1124 [POI2008]枪战Maf 贪心

    [POI2008]枪战Maf Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 741  Solved: 295[Submit][Status][Disc ...

  2. BZOJ 1124: [POI2008]枪战Maf(构造 + 贪心)

    题意 有 \(n\) 个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪. 因此,对于不同的开枪顺序,最后死的人也不同. 问最 ...

  3. 【刷题】BZOJ 1124 [POI2008]枪战Maf

    Description 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的人也不同. ...

  4. 【BZOJ】1124: [POI2008]枪战Maf

    题意 \(n(n < 1000000)\)个人,每个人\(i\)指向一个人\(p_i\),如果轮到\(i\)了且他没死,则他会将\(p_i\)打死.求一种顺序,问死的人最少和最多的数目. 分析 ...

  5. [POI2008]枪战Maf

    [POI2008]枪战Maf 题目 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的 ...

  6. 【BZOJ1124】[POI2008]枪战Maf 贪心+思路题

    [BZOJ1124][POI2008]枪战Maf Description 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开 ...

  7. [POI2008]枪战Maf题解

    问题 C: [POI2008]枪战Maf 时间限制: 1 Sec  内存限制: 256 MB 题目描述 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺 ...

  8. BZOJ1124 [POI2008]枪战Maf[贪心(证明未完成)+拓扑排序]

    吐槽:扣了几个小时,大致思路是有了,但是贪心的证明就是不会, 死磕了很长时间,不想想了,结果码代码又不会码.. 深深体会到自己码力很差,写很多行还没写对,最后别人代码全一二十行,要哭了 以下可能是个人 ...

  9. 【BZOJ 1124】[POI2008] 枪战Maf Tarjan+树dp

    #define int long long using namespace std; signed main(){ 这个题一看就是图论题,然后我们观察他的性质,因为一个图论题如果没有什么性质,就是真· ...

随机推荐

  1. IE8以下不支持getElementsByClassName方法

    function getElementsByClassName(classStr,tagName,element){ tagName = (tagName || '*'); element = (el ...

  2. nfs服务部署记录

    一.概念介绍NFS 是Network File System的缩写,即网络文件系统.一种使用于分散式文件系统的协定,由Sun公司开发,于1984年向外公布.功能是通过网络让不同的机器.不同的操作系统能 ...

  3. web.config connectionStrings 数据库连接字符串的解释(转载)

    先来看一下默认的连接SQL Server数据库配置 1.默认生成 <connectionStrings> <add name="Exa*DB" connectio ...

  4. usb驱动开发22之驱动生命线

    我们总是很喜欢高潮,不是吗?那就好好对待她哦.我们来看一下linux中的高潮部分设备是怎么从Address进入Configured的. usb_set_configuration函数的代码就不贴了,可 ...

  5. 尝试HTML + JavaScript 编写Windows App

    一直以来博文中使用最多的就是C# + XAML.进入Windows App时代,又多了一对 Javascript + HTML组合,这对于Web开发的程序员来说再熟悉不过了.其实小编也做过几年的Web ...

  6. 【转】Sql Server参数化查询之where in和like实现详解

    转载至:http://www.cnblogs.com/lzrabbit/archive/2012/04/22/2465313.html 文章导读 拼SQL实现where in查询 使用CHARINDE ...

  7. (原创)解决Excel 互操作错误"检索COML类工厂中 CLSID为 {00024500-0000-0000-C000-000000000046}的组件时失败,原因是出现以下错误: 80070005"

    最近在.net中处理Excel文件数据导入时报出以下错误: 检索COML类工厂中 CLSID为 {00024500-0000-0000-C000-000000000046}的组件时失败,原因是出现以下 ...

  8. 线程本地变量ThreadLocal源码解读

      一.ThreadLocal基础知识 原始线程现状: 按照传统经验,如果某个对象是非线程安全的,在多线程环境下,对对象的访问必须采用synchronized进行线程同步.但是Spring中的各种模板 ...

  9. 使用Netty绑定一个端口如何分辨出多种类型的DTU的注册包

    一.  背景 项目需要使用Netty和DTU(无线数据传输模块)通信,需要接入多种类型的DTU,每种dtu连接上来之后都首先会发送一个注册报文.需要解析该注册报文来实现: 1. 分辨出是哪种类型的dt ...

  10. 关于code reiview

    先谈谈三个code review的关键因素: 一.创建review要简单 code reivew是一个程序员日常工作中经常做的一件事,理论上来讲,任何一个将要submit到SCM的change,都必须 ...