系列题解总述
最近一周都在刷历年的APIO题,发现网上APIO的题解并不是很多,正好做了感觉这些题都挺有意思的,于是准备发一个APIO2007到2015年这9年题目的题解集合(好像还没人做过这件事情……)APIO给我的感觉是有很多题比较考思维,也有写起来需要很多细节的题。有意思的是,APIO并没有出现过中国特色数据结构(给你一个序列,支持XXXX操作,来个可持久化树套树看出题人心情带不带垃圾回收……),尽管2010年是中国出题;相反,APIO中很多题目是贪心和DP,这也是能够充分考验一个选手的分析能力的题目类型。
另外:之后的题目中,如果出现了【上古预警】,则代表这些题目是作者很早的时候做的,记忆可能比较搓,方法比较笨,代码风格可能比较丑……
风铃【上古预警】
首先由于层数在交换过程中不能变化,显然如果一开始就存在相差超过2层的情况必然无解。
然后考虑“合并”两个分支的情况。现在风铃有可能在上一层(我们定义为“高”),也可能在下一层(我们定义为“矮”)。我们认为一个子树具有三种状态:纯高,纯矮和 高矮兼有。令f[x]为x子树交换成满足条件的交换次数,则显然有f[x]=f[son1]+f[son2]+k,k视两边的情况而定。
下面是具体情况:(下面只介绍左右儿子均有的情况,只有一个儿子的情况留给读者自行思考)
1、左边复杂,右边纯高,k=0;
2、左边复杂,右边纯矮,k=1;
3、左右一样,k=0;
4、左边纯高,k=1;
5、右边纯矮,k=1;
然后就是注意特判和爆栈的问题了。作者写这个代码的时候还没学手工栈,所以用了一种讨巧的方法(详见代码)
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
using namespace std;
//基本思路:判断无解:首先如果在图中一开始就有层数差距大于1,则不可能成功。
//否则,肯定是能成功的。
//这样我们可以对左右的“纯”和“不纯”进行讨论
int n,maxd=0,mind=999999999,deep[100005]={0},d[100005]={0},l[100005]={0},r[100005]={0};
int f[100005]={0};
bool high[100005]={0};
int pure[100005]={0};
void input()
{scanf("%d",&n);
for(int i=1;i<=n;i++)
{scanf("%d%d",&l[i],&r[i]);
}
}
void dfs(int x,int depth)
{deep[x]=depth;
//cout<<x<<' '<<depth<<endl;
if(l[x]==-1||r[x]==-1)
{maxd=max(maxd,depth+1),mind=