码迷,mamicode.com
首页 > 其他好文 > 详细

【学术篇】luogu1351 [NOIP2014提高组] 联合权值

时间:2018-02-04 11:10:47      阅读:142      评论:0      收藏:0      [点我收藏+]

标签:++   广告   不用   建议   pid   for   ==   href   char   

一道提高组的题。。。。。
传送门:题目在这里。。。。

现在都懒得更自己的blog了,怕是太颓废了_ (:з」∠) _

好久没做题了,手都生了。(好吧其实是做题方面手太生了)

这题我都不想讲了,把代码一贴就算了呗。。

但还是要说说的。。。。
首先,题目里说:“无向连通图G 有n 个点,n - 1 条边。”
我们可以知道这是一棵树(怕不是废话。。),这样遍历的时候就能保证是O(n)级别了。。

找最大值 很简单,遍历树的时候找一下与每个点相连的点的最大值和次大值一乘就完了。。。显然这么贪心是没问题的。。。

求和 稍微麻烦一点,但也没多麻烦。。
然后呢,“对于图G 上的点对( u, v) ,若它们的距离为2 ”
这就分为两种情况。。。
我们假定以1为根(这样就能分出父子关系),与x距离为2就分为x和x的祖父和x和x的兄弟两种。。
x和x的祖父的联合权值好算(因为只有一个),遍历的时候记录一下父亲然后查一下就完了。
x和x的兄弟稍微麻烦一点,聪明的人是不会一个一个算的,因为这样会是O(n2)级别的。

这就要搬出一个公式来了,(不知道怎么想到这一点的。。但是正确性不言而喻,不信可以自己推推。。)
\[\sum_{i=L}^{R}\sum_{j=i+1}^{R}a_i*a_j=\frac{(\sum_{i=L}^{R}a_i)^2-\sum_{i=L}^{R}a_i^2}{2}\]

其实就是这个意思(我拿3个点举个例子吧~)
有3个点abc我们要求ab+ac+bc的时候,我们可以求出a+b+c①和a2+b2+c2②,然后(①2-②)/2即得。。

这个和和平方和我们是可以在能接受的时间内算出的。。
以上加起来就得到了代码。。我用bfs写的。。不过建议你们用dfs写就行了(这又不是会爆栈的什么省选)

然后题目说的是 “有序点对”(说明里就能看出来) 所以ans最后要2。。。(2后记得再取一次模不然会被卡到50)
然后就是最大值不用取模而求和需要取模(语文问题),这样用代码实现就可以AC啦~(≧▽≦)/~

然后这次的程序我是用QtCreator写的(Windows啦)。。。。(好像还配置了半天,调试器还没弄好)个人感觉界面很友好。。字体看着非常顺眼,补全也挺贴心的。。似乎也不像vs毛病特别多。。
(但换一个IDE就要换一下编译运行的快捷键也是很醉)~~~~
以上一段算是广告(当然没有广告费)纯属给大家安利一下,没有任何卵用,并不重要。。

我们上代码吧。。

#include <cstdio>
#include <queue>

using std::queue;
queue<int> q;
const int p=10007;
const int N=200020;
struct edge{
    int to,next;
};
edge e[N<<1]; int v[N],tot=0;
int fa[N],w[N];
bool vis[N];
int ans=0,maxn=0;

inline int max(const int &a,const int &b){
    if(a<b) return b; return a;
}

inline int getnum(){
    int a=0;char c=getchar();bool f=0;
    for(;(c<'0'||c>'9')&&c!='-';c=getchar());
    if(c=='-') c=getchar(),f=1;
    for(;c>='0'&&c<='9';c=getchar()) a=(a<<1)+(a<<3)+c-'0';
    if(f) return -a; return a;
}

void build(int from, int to){
    e[++tot].to=to; e[tot].next=v[from]; v[from]=tot;
}

void bfs(){
    while (!q.empty()) {
        int x=q.front(); q.pop(); vis[x]=1;
        long long numa=0,numb=0;
        int mx1=0,mx2=0;
        ans=(ans+w[x]*w[fa[fa[x]]])%p;
        for(int i=v[x];i;i=e[i].next){
            int y=e[i].to;
            if(w[y]>mx1) mx2=mx1,mx1=w[y];
            else mx2=max(mx2,w[y]);
            if(!vis[y]){
                q.push(y); fa[y]=x;
                numa+=w[y]; numb+=w[y]*w[y];
            }
        }
        long long _=(numa*numa-numb)>>1;
        ans=(ans+_)%p;
        maxn=max(maxn,mx1*mx2);
    }
}

int main(){
    int n=getnum();
    for(int i=1;i<n;i++){
        int a=getnum(),b=getnum();
        build(a,b); build(b,a);
    }
    for(int i=1;i<=n;i++) w[i]=getnum();
    q.push(1); bfs();
    printf("%d %d",maxn,(ans<<1)%p);
}

唔 就是这样。。
TG组的题对我来说还是太难了。。
我还是太弱了。。

【学术篇】luogu1351 [NOIP2014提高组] 联合权值

标签:++   广告   不用   建议   pid   for   ==   href   char   

原文地址:https://www.cnblogs.com/enzymii/p/8412184.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!