#define int long long
using namespace std;
signed main(){
这个题一看就是图论题,然后我们观察他的性质,因为一个图论题如果没有什么性质,就是真·不可做......
每个疯子只有一个出度,因此我们YY一下:{
这是一个有向图,所以,我们可以Tarjan,然后我们把点分为强联通分量内,和强联通分量外,然后我们从强联通分量内的点开始走:{
我们一定会走回自己,而且在这条路上不会出轨,那么这个强联通分量里,有了一个环,我们继续看这个环,他不会往外申枝,因此他就是一个
有点特殊的仙人球。
}
我们再走强联通分量外的点:{
他如果不遇到环的话就会一直走下去,因为如果不遇到环,我们每走一步都进入和之前不一样的点,而且每个点都会有且只有一个出度,
所以每个强联通分量外的点都会走到环。
}
综上,这个图大概就是->O<-的类型(对于“联通”的一块,一定有且仅有一个环,其他不在环里的点都通向环,并且他们的路径,只有融合,没有分枝)。
}
所以我们考虑怎么找答案:{
我们先不考虑强联通分量,把那个环拆开,并且以每个环的每个点为根,那么我们发现我们把路径反向之后出现了许多有根树,这样的话....
树dp:{
开数组f[n][]:{
f[i][]:{
他活着,死的最多(少)的人。
}
f[i][]:{
他死了,死的最多(少)的人。
}
记得,我们的状态说的是,最终结果,这个要是理不清会很乱。
}
先考虑转移:{
f[i][]:{
他要是活着,他的爹就必须在最终状态为死,他的儿子也得死。
那么f[i][]=sigma(死了的孩儿们)
}
f[i][]:{
这东西没要求,因为你可以任意调整顺序,得到一大片人头。
那么f[i][]=sigma(Max(死儿子,活儿子));
}
}
此外还有两个坑点:{
入度为零的点,必活;儿子里面存在入度为零的点,必死。
这样的话我们赋Inf来表示不可行。(...................)
}
}
然后我们得到了,每个环内的点活或死所得到的最大(最小)值,然后我们根据刚才的结论(活活不相挨),进行线性dp:{
在这之前我们当然要把环上的点连续地放到一个数列里,然而这是个环,我们数列的首项和末项也是有瓜葛的,那么我们就需要再开一维表示
第一个点死活。
这里还有个坑:{
对于一个没有枝杈的环,那么他至少剩一个;
但是对于自换,必死。
}
}
}
这样我们写出这样一个屎代码就能过了,你要是去波兰源网main.edu.pl/en,或者bzoj的话,递归函数一定要开inline因为有两个原来有但是我们没有的点,
就是递归层数1000000,栈空间炸到出屎。
}
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#define MAXN 1000010
#define Inf 0x3f3f3f3f
using namespace std;
inline int read(){
int sum=;char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')sum=(sum<<)+(sum<<)+ch-'',ch=getchar();
return sum;
}
struct Via{
int to,next,w;
}c[MAXN<<];
int head[MAXN],t,Ans_Max,Ans_Min,n;
long long f[MAXN][];
int F[MAXN][][];
int Aim[MAXN];
int dfn[MAXN],low[MAXN],stack[MAXN],top,Time,num;
bool in[MAXN],special[MAXN];
vector<int> member[MAXN];
inline long long Min(long long x,long long y){
return x<y?x:y;
}
inline long long Max(long long x,long long y){
return x>y?x:y;
}
inline void add(int x,int y,int z){
c[++t].to=y,c[t].next=head[x],head[x]=t,c[t].w=z;
}
inline void Tarjan(int x){
dfn[x]=low[x]=++Time,stack[++top]=x,in[x]=;
for(int i=head[x];i;i=c[i].next)
if(c[i].w){
if(!dfn[c[i].to]){
Tarjan(c[i].to),low[x]=Min(low[x],low[c[i].to]);
}else if(in[c[i].to])
low[x]=Min(low[x],dfn[c[i].to]);
}
if(dfn[x]==low[x]){
int j;num++;
do{
j=stack[top--],in[j]=,member[num].push_back(j),special[j]=;
}while(j!=x);
if(member[num].size()==&&Aim[j]!=j){
member[num].clear(),num--,special[j]=;
}
}
}
inline void dfs(int x,int &sum){
int J=;
for(int i=head[x];i;i=c[i].next)
if(c[i].w==&&special[c[i].to]==){
dfs(c[i].to,sum),f[x][]+=f[c[i].to][],f[x][]+=Max(f[c[i].to][],f[c[i].to][]),J++;
}sum++;
if(J==&&special[x]==){ f[x][]=,f[x][]=-Inf; }
else f[x][]+=;
}
inline int Do_It(int No_){
int len=member[No_].size(),sum=;
for(int i=;i<len;i++)dfs(member[No_][i],sum);
if(len==)return f[member[No_][]][];
else{
if(sum==len)return len-;
F[][][]=f[member[No_][]][]<?-:f[member[No_][]][],F[][][]=-,F[][][]=f[member[No_][]][],F[][][]=-;
for(int i=;i<len-;i++){
F[i+][][]=(F[i][][]==-||f[member[No_][i]][]<)?-:(F[i][][]+f[member[No_][i]][]);
F[i+][][]=((F[i][][]==-&&F[i][][]==-)||f[member[No_][i]][]<)?-:(Max(F[i][][],F[i][][])+f[member[No_][i]][]);
F[i+][][]=(F[i][][]==-||f[member[No_][i]][]<)?-:(F[i][][]+f[member[No_][i]][]);
F[i+][][]=((F[i][][]==-&&F[i][][]==-)||f[member[No_][i]][]<)?-:(Max(F[i][][],F[i][][])+f[member[No_][i]][]);
}
register int ans=F[len-][][]+Max(f[member[No_][len-]][],f[member[No_][len-]][]);
if(F[len-][][]!=-)ans=Max(ans,F[len-][][]+f[member[No_][len-]][]);
if(F[len-][][]!=-)ans=Max(ans,F[len-][][]+f[member[No_][len-]][]);
if(F[len-][][]!=-)ans=Max(ans,F[len-][][]+f[member[No_][len-]][]);
return ans;
}
}
inline void Dfs(int x){
int J=;
for(int i=head[x];i;i=c[i].next)
if(c[i].w==&&special[c[i].to]==){
Dfs(c[i].to),f[x][]+=f[c[i].to][],f[x][]+=Min(f[c[i].to][],f[c[i].to][]),J++;
}
if(J==&&special[x]==){ f[x][]=,f[x][]=Inf; }
else f[x][]+=;
}
inline int Cao_It(int No_)
{
register int len=member[No_].size();
for(int i=;i<len;i++)Dfs(member[No_][i]);
if(len==)return f[member[No_][]][];
else{
F[][][]=f[member[No_][]][]>=Inf?Inf:f[member[No_][]][],F[][][]=Inf,F[][][]=f[member[No_][]][],F[][][]=Inf;
for(int i=;i<len-;i++){
F[i+][][]=(F[i][][]==Inf||f[member[No_][i]][]>=Inf)?Inf:(F[i][][]+f[member[No_][i]][]);
F[i+][][]=((F[i][][]==Inf&&F[i][][]==Inf)||f[member[No_][i]][]>=Inf)?Inf:(Min(F[i][][],F[i][][])+f[member[No_][i]][]);
F[i+][][]=(F[i][][]==Inf||f[member[No_][i]][]>=Inf)?Inf:(F[i][][]+f[member[No_][i]][]);
F[i+][][]=((F[i][][]==Inf&&F[i][][]==Inf)||f[member[No_][i]][]>=Inf)?Inf:(Min(F[i][][],F[i][][])+f[member[No_][i]][]);
}
int ans=F[len-][][]+Min(f[member[No_][len-]][],f[member[No_][len-]][]);
if(F[len-][][]!=Inf)ans=Min(ans,F[len-][][]+f[member[No_][len-]][]);
if(F[len-][][]!=Inf)ans=Min(ans,F[len-][][]+f[member[No_][len-]][]);
if(F[len-][][]!=Inf)ans=Min(ans,F[len-][][]+f[member[No_][len-]][]);
return ans;
}
}
inline void Init(){
n=read();for(int i=;i<=n;i++)Aim[i]=read(),add(i,Aim[i],),add(Aim[i],i,);
for(int i=;i<=n;i++)if(!dfn[i])Tarjan(i);
}
inline void Work(){
for(int i=;i<=num;i++)Ans_Max+=Do_It(i);
memset(f,,sizeof(f));for(int i=;i<=num;i++)Ans_Min+=Cao_It(i);
printf("%d %d",Ans_Min,Ans_Max);
}
int main(){
Init();
Work();
return ;
}

【BZOJ 1124】[POI2008] 枪战Maf Tarjan+树dp的更多相关文章

  1. BZOJ 1124: [POI2008]枪战Maf

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

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

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

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

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

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

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

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

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

  6. [POI2008]枪战Maf

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

  7. [POI2008]枪战Maf题解

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

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

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

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

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

随机推荐

  1. Laravel5.x 封装的上传图片类

    图片缩放需要用conposer安装 ImageManagerStatic类 可参考下面的地址安装: https://www.jb51.net/article/128159.htm 控制器里: 控制器里 ...

  2. flask(列表实现)

    在 index/views.py 中定义视图函数 在查询的时候,如果用户分类id传0,则不添加分类查询条件 @index_blu.route('/newslist') def get_news_lis ...

  3. DedeCMS V5.7sp2最新版本parse_str函数SQL注入漏洞

    织梦dedecms,在整个互联网中许多企业网站,个人网站,优化网站都在使用dede作为整个网站的开发架构,dedecms采用php+mysql数据库的架构来承载整个网站的运行与用户的访问,首页以及栏目 ...

  4. ctf题目writeup(9)

    继续刷题,找到一个 什么 蓝鲸安全的ctf平台 地址:http://whalectf.xin/challenges (话说这些ctf平台长得好像) 1. 放到converter试一下: 在用十六进制转 ...

  5. go学习笔记-常见命令

    常见命令 go 命令 可以在控制台执行go来查看 go Go is a tool for managing Go source code. Usage: go <command> [arg ...

  6. HDU暑假多校第四场J-Let Sudoku Rotate

    一.题意 Sudoku is a logic-based, combinatorial number-placement puzzle, which is popular around the wor ...

  7. 2007: [Noi2010]海拔

    2007: [Noi2010]海拔 https://www.lydsy.com/JudgeOnline/problem.php?id=2007 分析: 平面图最小割. S在左下,T在右上,从S到T的一 ...

  8. 使用uniflash串口烧写CC3200的常见问题

    1. 在正常情况下,cc3200的烧写使用的是芯片的PIN55和PIN57,只要把SOP2上拉既可正常烧写,常见问题是烧写的时候没有上拉SOP2,正常运行SOP2留空,IAR只能仿真调试,不能下载程序 ...

  9. FJOI 2019 游记

    (FJOI 2019 滚粗记) Day 0 早上刷了一些水题,然后就上路了. (画图3D好好玩) 来得晚只有十几分钟时间看考场,于是连试机题都没有Ak. Day 1 果然我还是太菜了 走过来的时候再讨 ...

  10. 分布式文件系统---GlusterF

      1.1 分布式文件系统 1.1.1 什么是分布式文件系统 相对于本机端的文件系统而言,分布式文件系统(英语:Distributed file system, DFS),或是网络文件系统(英语:Ne ...