今天我进步了吗?没有。

好久没上博客骂(傻逼的)自己了呢。
今天的混更,是一道普及+/提高的题目。
https://www.luogu.org/problem/show?pid=1351(我已经放弃垃圾博客园的阉割版markdown的链接功能了

对于30% 的数据,1 < n≤ 100 ;
对于60% 的数据,1 < n≤ 2000;
对于100%的数据,1 < n≤ 200 , 000 ,0 < wi≤ 10, 000 。

我个人觉得呢,这个题的评级呢还是很准的

难呢,不是它的问题,很有可能是你的问题

这题包含了我个人的几乎所有我能想象到的能够令我大喊“Mitchie M P”的恶心地方。

说到这个,来个题外话
acg.tv/14065638

我放一下我的心路历程
评测记录
我刚开始呢,本着热身(其实是暂时懒得动脑想)的心态,直接暴力

从每个点开始dfs,到孙子就计算,return ;

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
inline void in(int &p,char c=getchar())
{
    while(c<'0' or c>'9')
        c=getchar();
    p=0;
    while(c>='0' and c<='9')
        p=p*10+c-'0',c=getchar();
}
inline void inl(long long &p,char c=getchar())
{
    while(c<'0' or c>'9')
        c=getchar();
    p=0;
    while(c>='0' and c<='9')
        p=p*10+c-'0',c=getchar();
}
bool cal[2001][2001],map[2001][2001],vis[2001];//数组我都懒得开大
int n;
long long mquan,squan,w[2001];//w,权值。mquan==max quan,最大权值。squan==sum quan,权值和。
const int mo=10007;
void dfs(int st,int here,int deep)
{
    if(deep>2)
        return ;
    vis[here]=1;
    if(deep==2 and !cal[st][here])
    {
        long long a=w[st]*w[here];
        mquan=max(mquan,a);
        squan+=a;
        if(squan>mo)
            squan%=mo;
        cal[st][here]=1;
        return ;
    }
    for(int i=1;i<=n;i++)
        if(map[here][i] and !vis[i])
            dfs(st,i,deep+1);
}
int main()
{
    in(n);
    for(int i=0;i<n-1;i++)
    {
        int a,b;
        in(a);in(b);
        map[a][b]=map[b][a]=1;
    }
    for(int i=1;i<=n;i++)
        inl(w[i]);
    for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof(vis));
        dfs(i,i,0);
    }
    printf("%lld %lld",mquan,squan);
    return 0;
}

闪闪亮亮的60分!在赛场上我觉得我已经圆满了,可以停了。
因为在后面写正解的过程中我不断产生新的problem我very担心赛场上我也这样最后爆0
所以还是加个

if(n>2001)
{
    //乱写的自以为的正解
}
else
{
    //直接暴力部分分
}

比较好呢!
正解应该是:
分析dfs中的一个点,它或与它相关的点产生贡献的方式只有2种:

1.自己与自己的爷爷(爸爸的爸爸叫爷爷,爸爸的妈妈叫奶奶
2.自己的儿子之间(哇听起来好奇怪nnsz!

这些都是dfs就可以搞定的!
爷爷,爸爸都可以顺便记录
儿子之间也很方便算:

设一个节点有N个儿子:son1,son2,son3,son4,...,sonN
(son1+son2+...+sonN)(son1+son2+...+sonN)-son12-son22-...-sonN^2=儿子之间的值(不需要再2)
儿子们中的最大联合权值,一定是由最大的单点权值X第二大的单点权值得来的

大家可以颅内感受一下是不是这样的。(是)。那么我们只需要在暴力代码上修改一点点(

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
inline void in(int &p,char c=getchar())
{
    while(c<'0' or c>'9')
        c=getchar();
    p=0;
    while(c>='0' and c<='9')
        p=p*10+c-'0',c=getchar();
}
inline void inul(unsigned long long &p,char c=getchar())
{
    while(c<'0' or c>'9')
        c=getchar();
    p=0;
    while(c>='0' and c<='9')
        p=p*10+c-'0',c=getchar();
}
bool /*map[20001][20001],*/vis[200001];
vector <int> map[200001];//这里因为数据的原因,垃圾的邻接矩阵不再适合,我用vector[i]存与i相连的点
int n;
unsigned long long mquan,squan,w[200001];//w,权值。mquan==max quan,最大权值。squan==sum quan,权值和。
const unsigned int mo=10007;
void dfs(int gdad,int dad,int here,int deep)
{
    vis[here]=1;
    unsigned long long a,max1=0,max2=0;
    if(deep>=3)//如果deep小于3,说明它还没有爷爷,就不会和爷爷发生关系
    {
        a=w[gdad]*w[here];
        mquan=max(mquan,a);
        squan+=a*2;
        if(squan>=mo)
            squan%=mo;
    }
    a=0;
    if(!map[here].size())//最后我才发现,这句是没用的,因为每个点都至少有1个相连的点
        return ;
    if(map[here].size()>2)//如果size<=2,说明它只有最多2个点,一个是自己的爸爸,另一个是自己唯一的儿子,本题并不能自交
    {
        for(unsigned int i=0;i<map[here].size();i++)
        {	
            if(map[here][i]==dad)//我是你爸,请跳过别算
                continue;
            a+=w[map[here][i]];
            if(max1<=w[map[here][i]])//大家颅内感受一下这个比对逻辑
                max2=max1,max1=w[map[here][i]];
            else
                max2=max(max2,w[map[here][i]]);
        }
        /*if(a>=mo)
            a%=mo;*/
        //这个一定不能写!我所有的20分30分都是因为这个。如果在这里先mo,后面的结果会错,变成负数之类,即使加mo加成正数也是错的!!!
        a=a*a;
        for(unsigned int i=0;i<map[here].size();i++)
            if(map[here][i]!=dad)//我是你爸,请跳过别算
                a-=w[map[here][i]]*w[map[here][i]];
        while(a<0)
            a+=mo;
        mquan=max(mquan,max1*max2);
        squan=squan+a;
        if(squan>=mo)
            squan%=mo;
    }
    for(unsigned int i=0;i<map[here].size();i++)
        if(!vis[map[here][i]])
            dfs(dad,here,map[here][i],deep+1);
}
int main()
{
    //freopen("1.in","r",stdin);
    in(n);
    for(int i=0;i<n-1;i++)
    {
        int a,b;
        in(a);in(b);
        //map[a][b]=map[b][a]=1;
        map[a].push_back(b);
        map[b].push_back(a);
    }
    for(int i=1;i<=n;i++)
        inul(w[i]);
    dfs(0,0,(1+n)>>1,1);//选任何节点开始dfs都可以的
    printf("%lld %lld",mquan,squan);
    return 0;
}

这是最终ac版,各种注释,各种特判if,太丑了
今天也是划水的一天呢

posted @ 2017-10-28 22:33  syhien  阅读(140)  评论(0编辑  收藏  举报