沖刺Noip2017模擬賽7 解題報告——五十嵐芒果醬


1、二叉樹(binary)

1.二叉樹
(binary.cpp/c/pas)
【問題描述】
二叉排序樹或者是一棵空樹,或者是具有下列性質的二叉樹:
(1)若左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
(2)若右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
(3)左、右子樹也分別為二叉排序樹;
(4)沒有鍵值相等的結點。
完全二叉樹:只有最下面的兩層結點度能夠小於2,並且最下面一層的結點
都集中在該層最左邊的若干位置的二叉樹。
圖1中,(a)和(b)是完全二叉樹,(c)和(d)是非完全二叉樹。
給出N個數,且這N個數構成1至N的排列。現在需要你按順序構建一棵二叉
排序樹,並按照層次遍歷的方式輸出它,然后判斷它是否是一棵完全二叉樹。
【輸入格式】
輸入文件名為binary.in。
輸入文件包含兩行。第一行為一個正整數N;第二行為1至N的排列。
【輸出格式】
輸出文件名為binary.out。
輸出文件包含兩行。第一行為構建出的二叉排序樹的層次遍歷;第二行判
斷是否是完全二叉樹:若是輸出yes,否則輸出no。
【輸入輸出樣例1】
binary.in
10
7 9 8 4 6 2 10 1 5 3
binary.out
7 4 9 2 6 8 10 1 3 5
yes
【輸入輸出樣例2】
binary.in 
5
3 4 5 2 1
binary.out
3 2 4 1 5
no
【數據規模與約定】
對於100%的數據,1≤N≤20
題目

 

tag:模擬

思路:其實這道題沒有看上去那么復雜。插入的時候比節點大就往右走,反之往左走,走到頭了放進去,最后建個樹。判斷是不是完全二叉樹要看最大的節點是不是在自己應該在的位置,因為仔細觀察發現完全二叉樹是每一層從左往右一個一個放,每個節點的數值和編號應該相等(感謝dalao這句話的思路)。

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<queue>
 6 using namespace std;
 7 int maxx,list[30][30],tree[1<<21],deep,n;
 8 void insert(int o,int x)
 9 {
10     maxx=max(maxx,o);
11     if(!tree[o]){
12         tree[o]=x;
13         return;
14     }
15     if(x>tree[o]) insert(o<<1|1,x);
16     else insert(o<<1,x);
17 }
18 void dfs(int o,int f)
19 {
20     deep=max(deep,f);
21     if(tree[o<<1]){
22         list[f+1][++list[f+1][0]]=tree[o<<1];
23         dfs(o<<1,f+1);
24     }
25     if(tree[o<<1|1]){
26         list[f+1][++list[f+1][0]]=tree[o<<1|1];
27         dfs(o<<1|1,f+1);
28     }
29 }
30 int main()
31 {
32     //freopen("binary.in","r",stdin);
33     //freopen("binary.out","w",stdout);
34     int x;
35     scanf("%d",&n);
36     for(int i=1;i<=n;++i){
37         scanf("%d",&x);
38         insert(1,x);
39     }
40     list[1][1]=tree[1];
41     list[1][0]=1;
42     dfs(1,1);
43     for(int i=1;i<=deep;++i)
44         for(int j=1;j<=list[i][0];++j)
45             printf("%d ",list[i][j]);
46     puts("");
47     if(maxx!=n) puts("no");
48     else puts("yes");
49     return 0;
50 }

 

2、列車調度(manage)

【問題描述】
有N輛列車,標記為1,2,3,…,N。它們按照一定的次序進站,站台共有K個軌
道,軌道遵從先進先出的原則。列車進入站台內的軌道后可以等待任意時間后出
站,且所有列車不可后退。現在要使出站的順序變為N,N-1,N-2,…,1,詢問K的
最小值是多少。
例如上圖中進站的順序為1,3,2,4,8,6,9,5,7,則出站的順序變為
9,8,7,6,5,4,3,2,1。
【輸入格式】
輸入文件名為manage.in。
輸入共2行。
第 1 行包含1個正整數N,表示N輛列車。
第 2 行包含N個正整數,為1至N的一個排列,表示進站次序。
【輸出格式】
輸出文件名為manage.out。
輸出共1行,包含1個整數,表示站台內軌道數K的最小值。
【輸入輸出樣例1】
manage.in
3
1 2 3
manage.out
3
【輸入輸出樣例2】
manage.in
9
1 3 2 4 8 6 9 5 7
manage.out
5
【數據規模與約定】
對於 30%的數據,N≤10;
對於 70%的數據,N≤2000;
對於 100%的數據,N≤100000
題目

 

tag:二分查找

思路:單純模擬用時較長(但是O(n2)居然能過???),正解是構造非降序列,比如現在的序列是(5,6,9,11),要把10插入進去,5,6,9都比10小,11比10大就停在11后面,序列變成(5,6,9,10),雖然單個的數值改變了,但是原本的單調性沒變,因此我們可以二分查找第一個比要插入的數大的數(0011型)。

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<queue>
 6 #include<cstdlib>
 7 #define maxn 100010
 8 using namespace std;
 9 int n,a[maxn],f[maxn],ans=1;
10 int main()
11 {
12     //freopen("manage.in","r",stdin);
13     //freopen("manage.out","w",stdout);
14     scanf("%d",&n);
15     for(int i=1;i<=n;++i) scanf("%d",&a[i]);
16     f[1]=a[1];
17     for(int i=2;i<=n;++i){
18         int l=lower_bound(f+1,f+ans+1,a[i])-f;
19         f[l]=a[i];
20         ans=max(ans,l);
21     }
22     printf("%d",ans);
23     return 0;
24 }

 

 

3、保留道路(road)

【問題描述】
很久很久以前有一個國家,這個國家有N個城市,城市由1,2,3,…,N標號,
城市間有M條雙向道路,每條道路都有兩個屬性g和s,兩個城市間可能有多條道
路,並且可能存在將某一城市與其自身連接起來的道路。后來由於戰爭的原因,
國王不得不下令減小花費從而關閉一些道路,但是必須要保證任意兩個城市相互
可達。
道路花費的計算公式為wG*max{所有剩下道路的屬性g}+wS*max{所有剩下道
路的屬性s},其中wG和wS是給定的值。國王想要在滿足連通性的前提下使這個花
費最小,現在需要你計算出這個花費。
【輸入格式】
輸入文件名為road.in。
第一行包含兩個正整數N和M。
第二行包含兩個正整數wG和wS。
后面的M行每行描述一條道路,包含四個正整數u,v,g,s,分別表示道路連接
的兩個城市以及道路的兩個屬性。
【輸出格式】
輸出文件名為road.out。
輸出一個整數,表示最小花費。若無論如何不能滿足連通性,輸出-1。
【輸入輸出樣例】
road.in
3 3
2 1
1 2 10 15
1 2 4 20
1 3 5 1
road.out
30
【數據規模與約定】
對於 10%的數據,N≤10,M≤20;
對於 30%的數據,N≤100,M≤1000;
對於 50%的數據,N≤200,M≤5000;
對於 100%的數據,N≤400,M≤50000,wG,wS,g,s≤1000000000
題目

tag:最小生成樹、輕度玄學(霧)

思路:二維費用的kruskal,很有研究的價值。平時我們做的最小生成樹都只有一維,突然多了一個維度,而且還有系數,有點讓人手足無措,我們應當以什么標准來選擇,加和?乘積?比值?都不行吧,可以隨便舉反例。正解是,兩個權值g,s任選其一作為標准從小到大排序,比如選擇g就以g的大小排,再看s的大小,我們造一個棧,從底到頂s從小到大,每放一條邊調整棧中各邊的位置,做一遍kruskal,記錄答案,時間復雜度是O(nm)。

 

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #include<algorithm>
 5 #include<queue>
 6 #define maxn 100010
 7 #define ll long long
 8 #define inf 1ll<<60
 9 using namespace std;
10 int gmax,smax,n,m,G,S,fa[maxn],st[maxn],top,tot;
11 ll ans=inf;
12 struct Edge{
13     int u,v,g,s;
14 }e[maxn];
15 bool cmp(Edge x,Edge y)
16 {
17     return x.g<y.g;
18 }
19 int find(int x)
20 {
21     return x==fa[x]?x:fa[x]=find(fa[x]);
22 }
23 int main()
24 {
25     //freopen("road.in","r",stdin);
26     //freopen("road.out","w",stdout);
27     int u,v,g,s;
28     scanf("%d%d",&n,&m);
29     scanf("%d%d",&G,&S);
30     for(int i=1;i<=m;++i) scanf("%d%d%d%d",&e[i].u,&e[i].v,&e[i].g,&e[i].s);
31     sort(e+1,e+m+1,cmp);
32     for(int i=1;i<=m;++i){
33         int j=0;
34         for(j=1;j<=n;++j) fa[j]=j;
35         for(j=top;j>=1;--j)
36             if(e[st[j]].s>e[i].s)
37                 st[j+1]=st[j];
38             else break;
39         top++;
40         st[j+1]=i;
41         tot=0;
42         for(j=1;j<=top;++j)
43         {
44             int k1=find(e[st[j]].u),k2=find(e[st[j]].v);
45             if(k1!=k2){
46                 fa[k1]=k2;
47                 st[++tot]=st[j];
48             }
49             if(tot==n-1) break;
50         }
51         if(tot==n-1) ans=min(ans,1ll*e[i].g*G+1ll*e[st[n-1]].s*S);
52         top=tot;
53     }
54     if(ans==inf) printf("-1");
55     else printf("%I64d",ans);
56     return 0;
57 }

————————————————懶得打分割線啊——————————————————

芒果君:考了這么多次,這場翻車最厲害,都倒數了QAQ 還是想太多


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM