1. 程式人生 > >【學術篇】luogu1351 [NOIP2014提高組] 聯合權值

【學術篇】luogu1351 [NOIP2014提高組] 聯合權值

https mat 父親 ans 級別 pop isp etc 取模

一道提高組的題。。。。。
傳送門:題目在這裏。。。。

現在都懶得更自己的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提高組] 聯合權值