noip2014 提高組題解 link

2021-06-27 01:08:07 字數 3739 閱讀 8873

題目描述:

聯合權值 

( link. cpp/c/pas)  

【問題描述

】 無向連通圖g 有n 個點,n - 1 條邊。點從1 到n 依次編號,編號為 i 的點的權值為w i   ,每條邊的長度均為1 。圖上兩點( u ,  v ) 的距離定義為u 點到v 點的最短距離。對於圖g 上的點對( u, v) ,若它們的距離為2 ,則它們之間會產生wu*wv的聯合權值。

請問圖g 上所有可產生聯合權值的有序點對中,聯合權值最大的是多少?所有聯合權

值之和是多少? 

【輸入】 

輸入檔名為link .in。 

第一行包含1 個整數n 。 

接下來n - 1 行,每行包含 2 個用空格隔開的正整數u 、v ,表示編號為 u 和編號為v 的點之間有邊相連。 

最後1 行,包含 n 個正整數,每兩個正整數之間用乙個空格隔開,其中第 i 個整數表示圖g 上編號為i 的點的權值為w i 。 

【輸出】 

輸出檔名為link .out 。 

輸出共1 行,包含2 個整數,之間用乙個空格隔開,依次為圖g 上聯合權值的最大值和所有聯合權值之和。由於所有聯合權值之和可能很大,輸出它時要對10007 取餘。

解題思路:

說實話我不想說其他分的做法。。。(其實是我不會。。。。。)

這道題目有多重演算法。。。。蒟蒻的我只會樹形dp,。。。。。。。。

首先看一看資料,n<=200000,臥槽這tm坑爹啊,居然不能打鄰接矩陣,所以果斷鄰接表搞起啊。。。。。。。。說實話鍊錶這東西我無力吐槽了。。。。。。。。(鄰接表不會寫的大爺請自行查閱。。。。由於本人水平問題無法描述。。。。。)

解決了邊的問題後,就開始進入正題。

事實上,雖說是樹形dp,但是我們只需要進行一次dfs就行了,不需要真正的構樹。我們只需要隨便抓乙個點作為根在進行樹的遍歷就行了。那麼接下來我就預設以1為根節點。

因為是距離為2的有序點對,所以對於乙個節點,它只有可能和它的爺爺、孫子、還有兄弟構成聯合權值。

考慮好這些之後,我們就有乙個大體的思路。那麼怎麼實現呢?

首先在遍歷是我們需要在dfs時維護一些值:sum[i](i節點的所有兒子的和),max1[i](i節點的所有兒子的最大值),max2[i](i節點的所有兒子的次大值)我相信大家都會維護!

那麼如何用這些值來求解ans_sum和ans_max呢?

對於ans_sum:

對於ans_max:

吐槽:

話說我考試的之後自己作死,然後在windows下開了乙個一條鏈的極限資料,然後遞迴暴棧了,我就果斷人工棧搞起,但是事後發現我同學寫的dfs,他在考場上寫人工棧沒寫出來,然後直接交的暴力,但是***後來發現linux下不會暴棧,艹,壯哉我大linux。。。。。。下面附上我的**和同學的**

**1(本人的人工棧的醜**):

//本人是淳樸的c黨

#include #include #include #include #define max(a,b) (a>b?a:b)

#define min(a,b) (a>b?b:a)

struct tree

*h[200010]=,*t[200010]=;

int ans=0;

int w[200010]=;

int max=-2e9;

int n;

int f[200010]=;

int maxn[200010][4]=;

int hash[200010]=;

int zhan[200010]=;

struct tree * zhanp[200010]=;

int top=0;

void dfs()

if(zhanp[top]==null && top>1)

else if(w[zhan[top]]>maxn[zhan[top-1]][2])

maxn[zhan[top-1]][2]=w[zhan[top]];

}max=max(max,w[zhan[top-1]]*maxn[zhan[top]][1]);

ans=(long long)(ans+(long long)f[zhan[top]]*w[zhan[top-1]]%10007*2%10007)%10007;

}if(zhanp[top]==null)

}return;

}int main()

t[j]->p=null;

t[j]->num=q;

if(h[q]==null)

else

t[q]->p=null;

t[q]->num=j;

}for(i=1;i<=n;i++)

scanf("%d",&w[i]);

dfs();

printf("%d %d",max,ans%10007);

fclose(stdin);

fclose(stdout);

return 0;

}

**2(我同學的深搜**,來自"期待變成大神的owaski"):

//果然是大神,寫的c++,蒟蒻的我。。。。

#include #include #include #include #include #define max(a, b) (a>b?a:b)

using namespace std;

const int maxn = 200005, mod = 10007;

int n = 0;

int w[maxn] = ;

long long sumd[maxn] = , maxd[maxn] = ;

long long ansmax[maxn] = , anssum[maxn] = ;

int hash[maxn] = ;

struct biao

*edge[maxn] = , *t[maxn] = ;

void add(int u, int v)

}int top = 0;

void find(int cur)

maxdd = max(maxd[i->node], maxdd);

sumdd += sumd[i->node];

sumdd %= mod;

ansmax[cur] = max(ansmax[i->node], ansmax[cur]);

anssum[cur] += anssum[i->node];

anssum[cur] %= mod;

}

for(biao *i = edge[cur]; i != null; i = i->nxt)

if(hash[i->node] > hash[cur])

ansmax[cur] = max(ansmax[cur], max(maxdd*(long long)w[cur], maxd2*maxd[cur]));

anssum[cur] += (sumdd*(long long)w[cur])<<1;

anssum[cur] %= mod;

}int main()

for(int i = 1; i <= n; ++i) scanf("%d", w+i);

find(1);

printf("%d %d", (int)ansmax[1], (int)(anssum[1]%mod));

fclose(stdin);

fclose(stdout);

return 0;

}

noip2014 提高組題解 equation

題目大意 給定高次方程an x n a1 x 1 a0 0 求 1,m 區間內有多少個整數根 ai 10 10000,m 1000000,n 100 首先,在考試的時候由於我很弱,一看到ai的範圍我就傻了,果斷30分騙起 解題思路 1.30分 30分很好騙,直接暴力就行了 2.60分 因為我考試的時...

NOIP2014提高組 尋找道路

noip2014 提高組 day2 試題。在有向圖 g 中,每條邊的長度均為 1,現給定起點和終點,請你在圖中找一條從起點到終點的路徑,該路徑滿足以下條件 1 路徑上的所有點的出邊所指向的點都直接或間接與終點連通。2 在滿足條件 1 的情況下使路徑最短。注意 圖 g 中可能存在重邊和自環,題目保證終...

NOIP2014提高組 解方程

noip2014 提高組 day2 試題。已知多項式方程 a0 a1 x a2 x2 an xn 0 求這個方程在 1,m 內的整數解 n 和 m 均為正整數 輸入共 n 2 行。第一行包含 2 個整數 n m,每兩個整數之間用乙個空格隔開。接下來的 n 1 行每行包含乙個整數,依次為 a0,a1,...