題目描述:
聯合權值
( 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,...