1124: [POI2008]枪战Maf

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 659  Solved: 259
[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

不看数据范围可能看起来像是缩点树归的样子, 但是平常的 $O(n^2)$ 树归在这里显然需要 $\text{真-}Owys$ 才能过( $\text{-}Owys$大法好, $n^2$ 过 $5 \times 10^5$ )(雾

然后按照图论题的一般套路就该找规律了w(找不到规律就成了神tm不可做题了)

经过一波 $Tarjan$ 缩点后再YY我们可以得到以下结论:

首先对于最大死亡数来说:

当 $SCC$ 为一个点的最大死亡数在存在入边时为$1$, 否则为 $0$.

当 $SCC$ 为一个环的最大死亡数在存在入边时为 $SCC$ 中的结点数 $size$ , 否则为 $size-1$ (有一个点是无法杀死的)

当环存在入边时还要加上连入的环的结点数再减去其中的零入度结点(因为零入度结点不可能死亡).

然后是最小死亡数:

首先零入度结点必定无法杀死, 而零入度结点的目标必死. 所以我们可以在预处理时将零入度结点压入一个队列, 然后删除它和它的目标, 更新答案, 并将删掉的结点的目标的入度减去 $1$ . 因为杀死必死的人后可能它的目标的入度变成 $0$ 然后变成新的存活结点. 新的存活结点入队. 如此处理直至队列为空.

然后我们可以发现所有的链都会在这个过程中被处理掉, 也就是说图里应该删得只剩下几坨环了. 然后这时我们可以发现对于环来说, 若环中结点数为 $s$ , 则至少要死去 $\left \lceil \frac {s}{2} \right \rceil$ 个结点. (每次刚好隔开杀手, 隔一个死一个w)

如此处理即可求出最终解.

辣鸡分类讨论吃枣药丸(╯‵□′)╯︵┻━┻(雾

参考代码

GitHub

 #include <stack>
#include <queue>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm> const int MAXN=; int n;
int scc;
int Time;
int maxA;
int minA;
int dfn[MAXN];
int low[MAXN];
int size[MAXN];
int belong[MAXN];
int target[MAXN];
int inDegree[MAXN];
int inDegreeSCC[MAXN]; bool visited[MAXN]; std::stack<int> s; void Initialize();
void DFS(int); int main(){
std::queue<int> live;
Initialize();
for(int i=;i<=n;i++){
if(inDegree[i]==)
live.push(i);
}
while(!live.empty()){
int top=live.front();
live.pop();
visited[top]=true;
if(visited[target[top]])
continue;
minA++;
visited[target[top]]=true;
if((--inDegree[target[target[top]]])==&&!visited[target[target[top]]])
live.push(target[target[top]]);
}
for(int i=;i<=n;i++){
int cnt=;
if(!visited[i]){
int x=i;
do{
visited[x]=true;
cnt++;
x=target[x];
}while(x!=i);
}
if(cnt>)
minA+=(cnt+)/;
}
memset(visited,,sizeof(visited));
for(int i=;i<=n;i++){
if(dfn[i]==)
DFS(i);
}
for(int i=;i<=n;i++){
if(target[i]==i||belong[i]!=belong[target[i]])
inDegreeSCC[belong[target[i]]]++;
}
for(int i=;i<=scc;i++){
if(inDegreeSCC[i]>)
maxA+=size[i];
else
maxA+=size[i]-;
}
printf("%d %d\n",minA,maxA);
return ;
} void DFS(int root){
dfn[root]=low[root]=++Time;
visited[root]=true;
s.push(root);
if(visited[target[root]]){
low[root]=std::min(low[root],dfn[target[root]]);
}
else if(dfn[target[root]]==){
DFS(target[root]);
low[root]=std::min(low[root],low[target[root]]);
}
if(low[root]==dfn[root]){
scc++;
int top;
do{
top=s.top();
belong[top]=scc;
size[scc]++;
visited[top]=false;
s.pop();
}while(top!=root);
}
} inline void Initialize(){
scanf("%d",&n);
for(int i=;i<=n;i++){
scanf("%d",target+i);
inDegree[target[i]]++;
}
}

Backup

[BZOJ 1124][POI 2008] 枪战 Maf的更多相关文章

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

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

  2. bzoj 1112 poi 2008 砖块

    这滞胀题调了两天了... 好愚蠢的错误啊... 其实这道题思维比较简单,就是利用treap进行维护(有人说线段树好写,表示treap真心很模板) 就是枚举所有长度为k的区间,查出中位数,计算代价即可. ...

  3. BZOJ 1124: [POI2008]枪战Maf

    1124: [POI2008]枪战Maf Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 617  Solved: 236[Submit][Status ...

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

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

  5. [POI2008]枪战Maf

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

  6. [BZOJ 1013][JSOI 2008] 球形空间产生器sphere 题解(高斯消元)

    [BZOJ 1013][JSOI 2008] 球形空间产生器sphere Description 有一个球形空间产生器能够在n维空间中产生一个坚硬的球体.现在,你被困在了这个n维球体中,你只知道球 面 ...

  7. [POI 2008&洛谷P3467]PLA-Postering 题解(单调栈)

    [POI 2008&洛谷P3467]PLA-Postering Description Byteburg市东边的建筑都是以旧结构形式建造的:建筑互相紧挨着,之间没有空间.它们共同形成了一条长长 ...

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

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

  9. [POI2008]枪战Maf题解

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

随机推荐

  1. 如何写.gitignore只包含指定的文件扩展名

    # .gitignore # 首先忽略所有的文件 * # 但是不忽略目录 !*/ # 忽略一些指定的目录名 ut/ # 不忽略下面指定的文件类型 !*.c++ !*.cc !*.cp !*.cpp ! ...

  2. Angular2 不明真相第一个Demo例子

    如果不是去年换工作接触到AngularJS,估计是不会花时间去学习这个框架的,毕竟是前端的框架,不是自己熟悉的领域.但是为了混得下去,去年就学习了AngularJS的一些用法,当时还整理了一些积累 & ...

  3. JAVA基础之——版本控制系统之git

    1 版本控制系统是什么 当多人协作开发一套产品时,需要能够保证代码都能够共用,那么版本控制系统就应运而生. 2 GIT 当前用的比较多的是svn和git,本文以git为例进行讲解. git诞生于200 ...

  4. Ubuntu重启网卡的三种方法

    一.network利用root帐户# service network restart 或者/etc/init.d/networking restart 二.ifdown/ifup# ifdown et ...

  5. C#学习笔记-接口与抽象类

    namespace ClassLesson { class Program { static void Main(string[] args) { ); Console.WriteLine(perso ...

  6. JQuery 判断指定ID是否存在

  7. ECharts 柱状图顶部显示百分比

    1.引入jquery.js和echarts.js <script src="../jquery-1.8.3.min.js" type="text/javascrip ...

  8. Linux 新手入门常用命令

    1,增加用户:useradd mylinux passwd mylinux 添加你的用户密码 2,切换用户: su otheruser   (注意这种切换方式只是临时的,本质工作目录还在原来的用户目录 ...

  9. 爬虫day02

    s10day112 内容回顾: 第一部分:爬虫相关 1. 谈谈你对http协议的理解? 规范: 1. Http请求收发数据的格式 GET /index/ http1.1/r/nhost:xxx.com ...

  10. redis使用方式

    关于Jedis连接Linux上的redis出现 DENIED Redis is running in protected mode问题的解决方案 1.修改redis.conf配置文件,将绑定的ip地址 ...