简单prufer应用

【bzoj1005】

Description

  自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在
任意两点间连线,可产生多少棵度数满足要求的树?

Input

  第一行为N(0 < N < = 1000),
接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1

Output

  一个整数,表示不同的满足要求的树的个数,无解输出0

Sample Input

3
1
-1
-1

Sample Output

2

关于prufer序列这个定理的证明,

给出大佬博客http://hzwer.com/3272.html

我这里就给一个结论

写到代码里,OK!

#include<stdio.h>
#include<stdlib.h>
#include<string>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<set>
#include<vector>
#include<queue>
#include<map>
#define il inline
#define re register
using namespace std;
const int N=1111;
int n,m,p,d[N],ans[N],chk[N],pr[N],cnt[N],tot,l;
il void filt(){
    for(int i=2;i<=1000;i++) if(!chk[i]){
        pr[++tot]=i;
        for(int j=i+i;j<=1000;j+=i)
            chk[j]=1;
    }
}
il void add(int p,int v){
//    cout<<p<<"...
";
    for(int k=1;k<=p;k++){
        int x=k;
        for(int i=1;i<=tot;i++){
            if(x<=1) break;
            while(x%pr[i]==0){
                cnt[i]+=v;x/=pr[i];
            }
        }
    }
}
il void mul(int x){
//    cout<<x<<endl;
    for(int i=1;i<=l;i++)
        ans[i]*=x;
    for(int i=1;i<=l;i++){
        ans[i+1]+=ans[i]/1000000;
        ans[i]%=1000000;
    }
    while(ans[l+1]>0){
        l++;
        ans[l+1]+=ans[l]/1000000;
        ans[l]%=1000000;
    }
}
int main(){
    filt();
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&d[i]);
    }
    if(n==1){
        if(!d[1]) cout<<'1';
        else cout<<'0';
        return 0;
    }
    for(int i=1;i<=n;i++){
        if(!d[i]){
            printf("0");
            return 0;
        }
        if(d[i]==-1) m++;
        else{
            d[i]--;p+=d[i];    
        }
    }
    if(p>n-2){
        printf("0");
        return 0;
    }
    add(n-2,1);
    add(n-2-p,-1);
    for(int i=1;i<=n;i++)
        if(d[i]>0) add(d[i],-1);
    ans[1]=1;l=1;
/*    for(int i=1;i<=tot;i++)
        cout<<cnt[i]<<' ';
    cout<<endl;*/
    for(int i=1;i<=tot;i++){
        for(;cnt[i];cnt[i]--)
            mul(pr[i]);
    }
//    cout<<m<<endl;
    for(int i=1;i<=n-2-p;i++)
        mul(m);
    printf("%d",ans[l]);
    for(int i=l-1;i>=1;i--)
        printf("%06d",ans[i]);
    return 0;
}

【bzoj1430】

Description

一开始森林里面有N只互不相识的小猴子,它们经常打架,但打架的双方都必须不是好朋友。每次打完架后,打架的双方以及它们的好朋友就会互相认识,成为好朋友。经过N-1次打架之后,整个森林的小猴都会成为好朋友。 现在的问题是,总共有多少种不同的打架过程。 比如当N=3时,就有{1-2,1-3}{1-2,2-3}{1-3,1-2}{1-3,2-3}{2-3,1-2}{2-3,1-3}六种不同的打架过程。

Input

一个整数N。

Output

一行,方案数mod 9999991。

Sample Input

4

Sample Output

96

HINT

50%的数据N<=10^3。
100%的数据N<=10^6。

【soltuion】

这不是刚刚那题的弱弱弱化版?

#include<stdio.h>
#include<stdlib.h>
#include<string>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<set>
#include<vector>
#include<queue>
#include<map>
#define il inline
#define re register
#define mod 9999991
using namespace std;
typedef long long ll;
int n,ans=1;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n-2;i++)
        ans=(ll)ans*n%mod;
    for(int i=1;i<n;i++)
        ans=(ll)ans*i%mod;
    cout<<ans;
    return 0;
}

我不会告诉你这篇博客只是一个刷题记录

原文地址:https://www.cnblogs.com/ExiledPoet/p/7070530.html