zoukankan      html  css  js  c++  java
  • 今天我进步了吗?没有。

    好久没上博客骂(傻逼的)自己了呢。
    今天的混更,是一道普及+/提高的题目。
    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,太丑了
    今天也是划水的一天呢

  • 相关阅读:
    转载--详解tomcat配置
    MongoDB@入门一
    面试@单例模式
    单点登录系统(一)
    SublimeText3 初探(工欲善其事,必先利其器)
    UEFI+GPT 修复 win10启动
    悟空模式-java-建造者模式
    悟空模式-java-原型模式
    悟空模式-java-单例模式
    悟空模式-java-抽象工厂模式
  • 原文地址:https://www.cnblogs.com/syhien/p/7748403.html
Copyright © 2011-2022 走看看