bzoj1124[POI2008]枪战maf
这代码快写死我了.....死人最多随便推推结论。死人最少,每个环可以单独考虑,每个环上挂着的每棵树也可以分别考虑.tarjan找出所有环,对环上每个点,求出选它和不选它时以它为根的树的最大独立集(就是最多活下来的人数),然后环上每个点选或不选对应的是一个“价值”,这个价值是那个点挂着的树里最多存活人数。先全都不选环上的点,算出选和不选时最大独立集的差值,问题变成有一个环,环上有一堆数(那些差值),选出一些不相邻的数使得和最大,然后我按着bzoj2151种树写了个贪心....这个贪心的思路也很神,网上有很多题解.后来发现这个东西和“种树”还不一样,因为种树限制必须种m棵,这个选的个数不限,所以可以O(nlogn)降到O(n),不过这两种方法都能过。另外tarjan不加inline会RE.总之这个方法不太具备可写性.
UPD:现在发现我当时是把这题写成bzoj1040了,囧。
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;
const int maxn=1500005;
int aim[maxn];
struct edge{//反向建边
int to,next;
}lst[maxn],lst2[maxn];int len=1,len2=1;
int first[maxn],first2[maxn];
void addedge(int a,int b){
lst[len].to=b;
lst[len].next=first[a];
first[a]=len++;
}
void addedge2(int a,int b){
lst2[len2].to=b;
lst2[len2].next=first2[a];
first2[a]=len2++;
}
int T;
int s[maxn],low[maxn],dfn[maxn],indeg[maxn],top;
int belong[maxn],sz[maxn],cnt;
bool ins[maxn];
inline void tarjan(int x){
dfn[x]=low[x]=++T;
s[top++]=x;ins[x]=true;
if(!dfn[aim[x]]){
tarjan(aim[x]);
if(low[aim[x]]<low[x])low[x]=low[aim[x]];
}else if(ins[aim[x]]&&dfn[aim[x]]<low[x])low[x]=dfn[aim[x]];
if(low[x]==dfn[x]){
++cnt;
do{
ins[s[--top]]=false;
belong[s[top]]=cnt;
sz[cnt]++;
addedge2(cnt,s[top]);
}while(s[top]!=x);
}
}
bool die[maxn];
int f[2][maxn];//bool vis[2][maxn];//f[][]求活人数目
int max(int a,int b){
return a>b?a:b;
}
int q[maxn];bool vis[maxn];
void dp(int s){
int head=0,tail=0;
if(vis[s])return;
q[tail++]=s;
while(head!=tail){
int x=q[head++];vis[x]=true;
for(int pt=first[x];pt;pt=lst[pt].next){
if(!vis[lst[pt].to])q[tail++]=lst[pt].to;
}
}
for(int i=tail-1;i>=0;--i){
int x=q[i];
f[1][x]=1;
for(int pt=first[x];pt;pt=lst[pt].next){
if(belong[lst[pt].to]==belong[x])continue;
f[1][x]+=f[0][lst[pt].to];
if(die[lst[pt].to])f[0][x]+=f[0][lst[pt].to];
else f[0][x]+=max(f[0][lst[pt].to],f[1][lst[pt].to]);
}
}
}
int w[maxn];/*
int work(int num){//第num个SCC最多生还多少人。种树???
++T;
priority_queue<node> q;
int ans=0;//猜测SCC节点出栈是按照在环上的顺序
for(int i=1;i<=sz[num];++i){
nxt[i]=i+1;
pre[i]=i-1;
}
nxt[sz[num]]=1;pre[1]=sz[num];
int j=0;
for(int pt=first2[num];pt;pt=lst2[pt].next){
ans+=f[0][lst2[pt].to];
if(!die[lst2[pt].to])w[++j]=f[1][lst2[pt].to]-f[0][lst2[pt].to];
else w[++j]=0;
q.push(node(j));
}//for(int i=1;i<=j;++i)printf("%d ",w[i]);printf("\n");
while(!q.empty()){//最后一次拿出来的时候会出错吗?
node tmp=q.top();q.pop();
if(used[tmp.k]==T)continue;
if(w[tmp.k]<=0)break;
ans+=w[tmp.k];//printf("%d %d\n",tmp.k,w[tmp.k]);
w[tmp.k]=w[pre[tmp.k]]+w[nxt[tmp.k]]-w[tmp.k];//printf("w%d\n",w[tmp.k]);
used[pre[tmp.k]]=used[nxt[tmp.k]]=T;
if(pre[tmp.k]==nxt[tmp.k])break;
pre[tmp.k]=pre[pre[tmp.k]];nxt[tmp.k]=nxt[nxt[tmp.k]];
if(used[pre[tmp.k]]==T||used[nxt[tmp.k]]==T)break;
pre[nxt[tmp.k]]=tmp.k;nxt[pre[tmp.k]]=tmp.k;// printf("%d %d %d %d\n",w[1],w[2],w[3],w[4]);
q.push(node(tmp.k));
}//printf("%d\n",ans);
return ans;
}*/
int F[2][2][maxn];
int work(int num){
int j=0,ans=0;
for(int pt=first2[num];pt;pt=lst2[pt].next){
ans+=f[0][lst2[pt].to];
if(!die[lst2[pt].to])w[++j]=f[1][lst2[pt].to]-f[0][lst2[pt].to];
else w[++j]=0;
}
F[1][1][1]=w[1];F[0][0][1]=0;F[0][1][1]=F[1][0][1]=-0x3f3f3f3f;
for(int i=2;i<=j;++i){
F[0][1][i]=F[0][0][i-1]+w[i];
F[1][1][i]=F[1][0][i-1]+w[i];
F[0][0][i]=max(F[0][0][i-1],F[0][1][i-1]);
F[1][0][i]=max(F[1][0][i-1],F[1][1][i-1]);
}
return ans+max(F[0][0][j],max(F[0][1][j],F[1][0][j]));
}
int main(){
int n;scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d",aim+i);
//if(i==aim[i])die[i]=true;
//else
addedge(aim[i],i);
}
for(int i=1;i<=n;++i){
if(!dfn[i])tarjan(i);
}
for(int i=1;i<=n;++i){
if(belong[i]!=belong[aim[i]])indeg[belong[aim[i]]]++;
if(i==aim[i])indeg[belong[i]]++;
}
for(int i=1;i<=n;++i){
if(!first[i]){
die[aim[i]]=true;
}
}
for(int i=1;i<=n;++i){
dp(i);
}
int ans1=n;
for(int i=1;i<=n;++i){
if(aim[i]==i){
ans1-=f[0][i];
}
}
for(int i=1;i<=cnt;++i){
if(sz[i]>1){
ans1-=work(i);
}
}
int ans2=n;
for(int i=1;i<=cnt;++i){
if(!indeg[i])ans2--;
}
printf("%d %d\n",ans1,ans2);
return 0;
}
bzoj1124[POI2008]枪战maf的更多相关文章
- BZOJ1124 [POI2008]枪战Maf[贪心(证明未完成)+拓扑排序]
吐槽:扣了几个小时,大致思路是有了,但是贪心的证明就是不会, 死磕了很长时间,不想想了,结果码代码又不会码.. 深深体会到自己码力很差,写很多行还没写对,最后别人代码全一二十行,要哭了 以下可能是个人 ...
- BZOJ1124 POI2008枪战Maf(环套树+贪心)
每个点出度都为1,可以发现这张图其实是个环套树森林,树中儿子指向父亲,环上边同向. 首先自环肯定是没救的,先抬出去. 要使死亡人数最多的话,显然若一个点入度为0其不会死亡,而一个孤立的环至少会留下一个 ...
- 【BZOJ1124】[POI2008]枪战Maf 贪心+思路题
[BZOJ1124][POI2008]枪战Maf Description 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开 ...
- BZOJ 1124: [POI2008]枪战Maf
1124: [POI2008]枪战Maf Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 617 Solved: 236[Submit][Status ...
- [POI2008]枪战Maf
[POI2008]枪战Maf 题目 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的 ...
- bzoj 1124 [POI2008]枪战Maf 贪心
[POI2008]枪战Maf Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 741 Solved: 295[Submit][Status][Disc ...
- [POI2008]枪战Maf题解
问题 C: [POI2008]枪战Maf 时间限制: 1 Sec 内存限制: 256 MB 题目描述 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺 ...
- 【BZOJ1124】[POI2008]枪战Maf(基环树_构造)
被教练勒令做题不能看题解后的第一道新题,自行 yy 了好久终于 AC 了(菜啊)--写博客纪念. 题目: BZOJ1124 分析: 考虑每个人向他要打的人连边.根据题意,所有点都有且只有一条出边.那么 ...
- 【BZOJ】1124: [POI2008]枪战Maf
题意 \(n(n < 1000000)\)个人,每个人\(i\)指向一个人\(p_i\),如果轮到\(i\)了且他没死,则他会将\(p_i\)打死.求一种顺序,问死的人最少和最多的数目. 分析 ...
随机推荐
- 小图标外链API
网页上有些分享的小图标,比如分享到facebook,weibo,qq空间等功能的时候,图标以前一般是自己做一个css sprite.当一个网站的图标变了的时候,比如facebook变成assbook的 ...
- 清北学堂2017NOIP冬令营入学测试P4747 D’s problem(d)
时间: 1000ms / 空间: 655360KiB / Java类名: Main 背景 冬令营入学测试题 描述 题目描述 小D是一名魔法师,它最喜欢干的事就是对批判记者了. 这次记者招待会上,记者对 ...
- java:如何让程序按要求自行重启?
正文开始前的废话: 这里的程序即包括b/s的web application,也包括standalone的类c/s的java application. 为什么要自我重启? 场景1:分布式环境中, ...
- sublime 函数跳转插件 — ctags 安装和使用
ctags 是 sublime 下一个函数跳转的插件,可以让你方便地从函数调用的位置跳到函数定义的位置.相对于其他插件,ctags 的安装稍微有点复杂,这里记录下备忘. 首先,假设已经安装 Packa ...
- node 学习笔记 - Modules 模块加载系统 (2)
本文同步自我的个人博客:http://www.52cik.com/2015/12/14/learn-node-modules-module.html 上一篇讲了模块是如何被寻找到然后加载进来的,这篇则 ...
- ASP.NET MVC 多语言实现技巧 最简、最易维护和最快速开发
说说传统做法的缺点 1.做过多语言的都知道这玩意儿太花时间 2.多语言架构一般使用资源文件.XML或者存储数据库来实现.这样就在一定程序上降低了性能 3.页面的可读性变差,需要和资源文件进行来回切换 ...
- 论javascript中的原始值和对象
javascript将数据类型分为两类:原始值(undefined.null.布尔值.数字和字符串),对象(对象.函数和数组) 论点:原始值不可以改变,对象可以改变:对象为引用类型: '原始值不可以改 ...
- ALinq Dynamic 使用指南——代码的获取与编译
1.下载代码 ALinq Dynamic 项目托管在 CodePlex 网站,你可以使用浏览器下载压缩包,或者通过 SVN 获取. 项目网址:http://esql.codeplex.com/ 压缩包 ...
- android开发------Activity生命周期
这几天工作比较忙,基本没有什么时间更新播客了. 趁着今晚有点时间,我们来简单说一下什么是Activity生命周期和它们各阶段的特征 什么是生命周期 在还没有接触android开发的时候,听到有人说Ac ...
- Oracle中可以nologging执行的操作
redo重做日志是Oracle数据库恢复(recovery)的基础:但在很多情况下可以通过禁用重做日志的产生来加速SQL语句的完成,也就是我们所说的可nologging化的操作,这些操作大多是或串行的 ...