bzoj1005: [HNOI2008]明明的烦恼

链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1005

题意:中文题。。。

分析:prufer序列的应用,因为题目已经限制了一些节点的度,那么我们只要在prufer序列里取出x[i]-1个位置给它即可,若prufer序列中还有sum个位置没有被分配节点编号,那么就是那没有度数限制的g个节点任意去即g^sum中方案。那么前面的组合数学*g^sum就是答案啦。

代码:

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<math.h>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
const int N=1020;
const int MAX=151;
const int MOD1=100000007;
const int MOD2=100000009;
const double EPS=0.00000001;
typedef long long ll;
const ll MOD=9999991;
const ll INF=10000000010;
typedef unsigned long long ull;
int a[N],bo[N],p[N][7],q[N][7];
void deal() {
    int i,j,w,k=0,n=1010;
    memset(bo,0,sizeof(bo));
    bo[1]=1;
    for (i=2;i<=n;i++) {
        if (!bo[i]) a[++k]=i;
        for (j=1;j<=k;j++) {
            if (a[j]*i>n) break ;
            bo[a[j]*i]=1;
            if (i%a[j]==0) break ;
        }
    }
    memset(p,0,sizeof(p));
    for (i=1;i<=k;i++) {
        w=a[i];
        while (w<=n) { p[w][0]++;p[w][p[w][0]]=a[i];w+=a[i]; }
    }
    memset(q,0,sizeof(q));
    for (i=1;i<=n;i++) {
        w=i;
        for (j=1;j<=p[i][0];j++) {
            while (w%p[i][j]==0) { q[i][j]++;w/=p[i][j]; }
        }
    }
}
int x[N],ans[N*100],num[N];
void add(int x) {
    for (int i=1;i<=p[x][0];i++) num[p[x][i]]+=q[x][i];
}
void sub(int x) {
    for (int i=1;i<=p[x][0];i++) num[p[x][i]]-=q[x][i];
}
int main()
{
    int i,j,k,g,n,flag=0,sum;
    scanf("%d", &n);
    deal();sum=n-2;g=0;
    for (i=1;i<=n;i++) {
        scanf("%d", &x[i]);
        if ((x[i]<1&&x[i]!=-1)||(x[i]>=n)) flag=1;
        if (x[i]!=-1) sum-=x[i]-1;
        else g++;
    }
    if (flag||sum<0||(g==0&&sum>0)) { printf("0\n");return 0; }
    memset(ans,0,sizeof(ans));
    ans[0]=ans[1]=1;
    for (i=1;i<=sum;i++) {
        for (j=1;j<=ans[0];j++) ans[j]*=g;
        for (j=1;j<ans[0];j++) { ans[j+1]+=ans[j]/10;ans[j]%=10; }
        while (ans[ans[0]]>9) { ans[ans[0]+1]=ans[ans[0]]/10;ans[ans[0]]%=10;ans[0]++; }
    }
    memset(num,0,sizeof(num));
    for (i=1;i<=n-2;i++) add(i);
    for (i=1;i<=sum;i++) sub(i);
    for (i=1;i<=n;i++)
    if (x[i]>1) {
        for (j=1;j<x[i];j++) sub(j);
    }
    for (i=1;i<=1000;i++)
    if (num[i]) {
        for (j=1;j<=num[i];j++) {
            for (k=1;k<=ans[0];k++) ans[k]*=i;
            for (k=1;k<ans[0];k++) { ans[k+1]+=ans[k]/10;ans[k]%=10; }
            while (ans[ans[0]]>9) { ans[ans[0]+1]=ans[ans[0]]/10;ans[ans[0]]%=10;ans[0]++; }
        }
    }
    for (i=ans[0];i>0;i--) printf("%d", ans[i]);printf("\n");
    return 0;
}

/*
3
1 -1 -1
4
-1 -1 -1 2
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值