由于一些奇奇怪怪的事情忙了好一段时间没有静下心来写东西,一年区域赛快要开始的时候啦现在再开始写真的米有问题么··?虽然之前做了很多比赛 也写了很多题目,但是总是感觉状态只能算是soso~ 无论如何还是好好努力一下吧!~ 开始刷bzoj写点东西吧
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1005
看到这题的时候会觉得好像没有什么思路嘤嘤嘤,后来偷偷的去瞄了一眼题解233 知道了有prufer编码这个神奇的东西。
prufer的编码是通过度作为创建“序”的索引,通过构造方法使得最终的序与某棵树的形态一一对应。
从树上确定prufer编码的方法是:
1.选取树上度为1的编号最小的节点。
2.将(1)中所选出的节点相连的点加入prufer序列。
3.将(1)中所选出的节点删除。
4.若剩下的树只有一条边则返回 否则继续进行(1)
上图的prufer序列就是 2 2 1 3
而反过来 如果要通过prufer序列去求一棵树则采用以下步骤
1.通过prufer序列求出每个节点的度数【获得度数表】。
2.(对于第i次操作)查找度数表中度数为1且编号最小的节点 ,将之与prufer序列中的第i个节点连边
3.将(2)中度数表中的点与prufer序列中的点的度数都减1
4.若度数表中仅剩两个元素度数非0将之连边,否则返回2
类似这样的一个过程,当然这题知道了这个过程之后,就可以将问题转化为:对于那些已经明确知道度数为多少的节点poi[i]
如果poi[i]==1 说明他们是叶节点 不可能出现在prufer序列中 反之需要求
import java.math.BigInteger;
import java.util.Scanner;
public class Main {
/**
* @param args
*/
static BigInteger C(int dow,int upe){
BigInteger ret=new BigInteger("1");
for (int c_i=dow;c_i>=dow-upe+1;c_i--)
ret=ret.multiply(BigInteger.valueOf(c_i));
for (int c_i=upe;c_i>=1;c_i--)
ret=ret.divide((BigInteger.valueOf(c_i)));
return (ret);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
BigInteger ans;
Scanner sc=new Scanner(System.in);
int a[]=new int[1500];
int n=sc.nextInt();
int sum=0,cnt=0;
for (int i=0;i<n;i++){
a[i]=sc.nextInt();
if (a[i]!=-1)
sum+=a[i];
else
cnt++;
}
if (sum-n>n-2){
System.out.println(-1);
return;
}
ans=BigInteger.valueOf(1);
int now=n-2;
for (int i=0;i<n;i++)
if (a[i]!=-1 && a[i]>1){
if ((a[i]-1)*2<=now)
ans=ans.multiply(C(now,a[i]-1));
else
ans=ans.multiply(C(now,now-(a[i]-1)));
now=now-(a[i]-1);
}
for (int i=0;i<now;i++)
ans=ans.multiply(BigInteger.valueOf(cnt));
System.out.println(ans.toString());
}
}
从这道题目的话感觉 对于树的记数其实都需要一个“序”,把一棵树对应成一个线性的结构才能比较好的进行操作。