prow2012-A3-0006

从 Trac 迁移的文章

这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。

原文章内容如下:

大意:删去一颗无根树的一个顶点,使分裂的各部分的点权和的乘积最大.

比赛时写的代码。很裸的树形DP,记录每个子数的点权和就行,需要用到高精度,比赛时第一次用zju的高精度模板,结果看懂模板后发现模板里没处理爆int的情况。后来改正后AC。

第二次用这模板是AC自动机的DP,也需要高精度,有了这次经验,第二次就顺利1A了。


{{{

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <iostream>
using namespace std;
#define DIGIT   4
#define DEPTH   10000
#define MAX     100
typedef long long bignum_t[MAX+1];
void write(const bignum_t a,ostream& os=cout){
        int i,j;
            for (os<<a[i=a[0]],i--;i;i--)
                        for (j=DEPTH/10;j;j/=10)
                                        os<<a[i]/j%10;
            printf("\n");
}
int comp(const bignum_t a,const bignum_t b){
        int i;
            if (a[0]!=b[0])
                        return a[0]-b[0];
                for (i=a[0];i;i--)
                            if (a[i]!=b[i])
                                            return a[i]-b[i];
                    return 0;
}
void mul(bignum_t a,const int b){
    int i;
    if (b==0) return ;
    for (a[1]*=b,i=2;i<=a[0];i++){
        a[i]*=b;
        if (a[i-1]>=DEPTH)
            a[i]+=a[i-1]/DEPTH,a[i-1]%=DEPTH;
    }
    for (;a[a[0]]>=DEPTH;a[a[0]+1]=a[a[0]]/DEPTH,a[a[0]]%=DEPTH,a[0]++);
    for (;!a[a[0]]&&a[0]>1;a[0]--);
}
int N,Num[110000],f[110000],father[110000];
int edge[110000],node[210000],next[210000],tot;
void insert(int a,int b){
    node[tot] = b,next[tot] = edge[a],edge[a] = tot++;
}
void dfs(int now,int fa){

    f[now] = Num[now];
    father[now] = fa;
    for (int i=edge[now];i!=-1;i=next[i])
    if (node[i]!=fa){
        dfs(node[i],now);
        f[now]+=f[node[i]];
    }
    return ;
}
bignum_t ans;

int main(){
    int i,j,a,b;
    while(scanf("%d",&N)!=EOF){
        tot = 0;
        for (i=1;i<=N;i++)
            scanf("%d",&Num[i]),edge[i] = -1;
        for (i=1;i<N;i++){
            scanf("%d%d",&a,&b);
            insert(a,b);
            insert(b,a);
        }
        if (N==1) {
            printf("0\n");
            continue;
        }
        dfs(1,0);
         ans;
        memset(ans,0,sizeof(ans));
        ans[0] = 1;
        bignum_t tmp;
        for (i=1;i<=N;i++){
                int fa = father[i];
            memset(tmp,0,sizeof(tmp));
            tmp[0] = 1;
            tmp[1] = 1;
            mul(tmp,f[1]-f[i]);
            for (j=edge[i];j!=-1;j=next[j])
                if (node[j]!=fa)
                {
                    mul(tmp,f[node[j]]);
                    //write(tmp);
                    //printf("%d %d\n",i,node[j]);
                }

            if (comp(tmp,ans)>0){
                for (j=tmp[0];j>=0;j--)
                    ans[j] = tmp[j];
            }
        }


        write(ans);



    }

}


}}}

大意:删去一颗无根树的一个顶点,使分裂的各部分的点权和的乘积最大.

比赛时写的代码。很裸的树形DP,记录每个子数的点权和就行,需要用到高精度,比赛时第一次用zju的高精度模板,结果看懂模板后发现模板里没处理爆int的情况。后来改正后AC。

第二次用这模板是AC自动机的DP,也需要高精度,有了这次经验,第二次就顺利1A了。

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <iostream>
using namespace std;
#define DIGIT   4
#define DEPTH   10000
#define MAX     100
typedef long long bignum_t[MAX+1];
void write(const bignum_t a,ostream& os=cout){
        int i,j;
            for (os<<a[i=a[0]],i--;i;i--)
                        for (j=DEPTH/10;j;j/=10)
                                        os<<a[i]/j%10;
            printf("\n");
}
int comp(const bignum_t a,const bignum_t b){
        int i;
            if (a[0]!=b[0])
                        return a[0]-b[0];
                for (i=a[0];i;i--)
                            if (a[i]!=b[i])
                                            return a[i]-b[i];
                    return 0;
}
void mul(bignum_t a,const int b){
    int i;
    if (b==0) return ;
    for (a[1]*=b,i=2;i<=a[0];i++){
        a[i]*=b;
        if (a[i-1]>=DEPTH)
            a[i]+=a[i-1]/DEPTH,a[i-1]%=DEPTH;
    }
    for (;a[a[0]]>=DEPTH;a[a[0]+1]=a[a[0]]/DEPTH,a[a[0]]%=DEPTH,a[0]++);
    for (;!a[a[0]]&&a[0]>1;a[0]--);
}
int N,Num[110000],f[110000],father[110000];
int edge[110000],node[210000],next[210000],tot;
void insert(int a,int b){
    node[tot] = b,next[tot] = edge[a],edge[a] = tot++;
}
void dfs(int now,int fa){
    f[now] = Num[now];
    father[now] = fa;
    for (int i=edge[now];i!=-1;i=next[i])
    if (node[i]!=fa){
        dfs(node[i],now);
        f[now]+=f[node[i]];
    }
    return ;
}
bignum_t ans;
int main(){
    int i,j,a,b;
    while(scanf("%d",&N)!=EOF){
        tot = 0;
        for (i=1;i<=N;i++)
            scanf("%d",&Num[i]),edge[i] = -1;
        for (i=1;i<N;i++){
            scanf("%d%d",&a,&b);
            insert(a,b);
            insert(b,a);
        }
        if (N==1) {
            printf("0\n");
            continue;
        }
        dfs(1,0);
         ans;
        memset(ans,0,sizeof(ans));
        ans[0] = 1;
        bignum_t tmp;
        for (i=1;i<=N;i++){
                int fa = father[i];
            memset(tmp,0,sizeof(tmp));
            tmp[0] = 1;
            tmp[1] = 1;
            mul(tmp,f[1]-f[i]);
            for (j=edge[i];j!=-1;j=next[j])
                if (node[j]!=fa)
                {
                    mul(tmp,f[node[j]]);
                    //write(tmp);
                    //printf("%d %d\n",i,node[j]);
                }
            if (comp(tmp,ans)>0){
                for (j=tmp[0];j>=0;j--)
                    ans[j] = tmp[j];
            }
        }
        write(ans);
    }
}