1. 程式人生 > >暑假第四次考試 沖刺Noip模擬賽4 解題報告——五十嵐芒果醬

暑假第四次考試 沖刺Noip模擬賽4 解題報告——五十嵐芒果醬

空格 註意 工程 tin tex app als family 如果

題1 韜韜搶蘋果(apple)

技術分享
【問題描述】
又到了收獲的季節,樹上結了許多韜韜,錯了,是許多蘋果,有很多個小韜韜都來摘蘋
果。每個韜韜都想要最大的蘋果,所以發生了爭執,為了解決他們的矛盾,出題人定了一項
特殊的規則,按體重的大小來定順序,每一輪都是先由胖的先摘(照顧胖子),每個韜韜都
是很聰明的,不會錯過眼前最大的蘋果。現在問題來了,一共有 n 個蘋果,m 個韜韜,要你
按原順序輸出每個韜韜可以搶到的蘋果的總大小。
【輸入格式】apple.in
第一行兩個數 n,m。
接下來一行 n 個數,分別為每個蘋果的大小。
接下來一行 m 個數,分別為每個韜韜的體重。
【輸出格式】apple.out
一行 m 個數,每個韜韜搶到的蘋果的大小。 【輸入樣例】 5 3 1 2 3 4 5 1 2 3 【輸出樣例】 3 5 7 【 數據規模 】 n,m<=100000
題目

 tag:模擬

 思路:模擬即可,為了防止被極端數據卡開了long long。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cmath>
 6 #define ll long long
 7 #define maxn 100010
 8
using namespace std; 9 ll ans[maxn]; 10 int ap[maxn],po,n,m; 11 struct TT{ 12 int w,id; 13 }tt[maxn]; 14 bool cmp1(int x,int y) 15 { 16 return x>y; 17 } 18 bool cmp2(TT x,TT y) 19 { 20 return x.w>y.w; 21 } 22 int main() 23 { 24 //freopen("apple.in","r",stdin); 25 //freopen("apple.out","w",stdout);
26 scanf("%d%d",&n,&m); 27 for(int i=1;i<=n;++i) scanf("%d",&ap[i]); 28 for(int i=1;i<=m;++i){ 29 scanf("%d",&tt[i].w); 30 tt[i].id=i; 31 } 32 sort(ap+1,ap+n+1,cmp1); 33 sort(tt+1,tt+m+1,cmp2); 34 int f=po=1; 35 while(1){ 36 for(int i=1;i<=m;++i){ 37 ans[tt[i].id]+=ap[po++]; 38 if(po>n){ 39 f=0; 40 break; 41 } 42 } 43 if(!f) break; 44 } 45 for(int i=1;i<=m;++i) cout<<ans[i]<<" "; 46 return 0; 47 }

題2 開場舞蹈(dance)

技術分享
【問題描述】
在全世界人民的期盼下,2008 年北京奧林匹克運動會終於隆重召開了!
為了展示中華民族博大精深的優秀傳統文化,負責開幕式開場舞蹈的編排人員一絲不
茍,每一個細節都力爭完美。關於隊伍是采用“天圓”陣還是“地方”陣的問題,大家討論
了七天七夜,仍沒有結果。於是,他們希望借助計算機,計算兩種陣型的成本。
隊伍將排列在一個二維平面內,且必須以(00)點為中心使得隊伍保持對稱美。“天
圓”陣是一個圓形,而“地方”陣則是一個邊平行於坐標軸的正方形。由於某種因素,陣型
要求覆蓋某些點(可以在邊上)。
你的任務是,計算出能夠覆蓋這些點的兩種陣型的最小面積。
【輸入文件】
輸入文件  dance.in。第一行是一個整數 n(1<=n<=100000),表示需要覆蓋的點的個數。
接下來 n 行,第 i 行是兩個整數 xi,yi(-1000<=xi,yi<=1000),表示第 i 個點的坐標位
置(xi,yi)。
【輸出文件】
輸出文件  dance.out。第一行是一個整數 s1,表示能夠覆蓋這些點的“天圓”陣的最小
面積(pi=3.14,四舍五入)。第二行是一個整數 s2,表示能夠覆蓋這些點的“地方”陣的
最小面積。
【樣例輸入】
4
0 0
0 2
5 0
8 0
【樣例輸出】
201
256
題目

tag:模擬

思路:取最大值,註意四舍五入的處理,乘10取整,再將mod10的結果與5比較。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cmath>
 6 #define ll long long
 7 #define maxn 100010
 8 using namespace std;
 9 const double pi=3.14;
10 int n,A,ans;
11 double R;
12 double cal(int x,int y){return sqrt((double)(x*x+y*y));}
13 int main()
14 {
15     //freopen("dance.in","r",stdin);
16     //freopen("dance.out","w",stdout);
17     int x,y;
18     scanf("%d",&n);
19     for(int i=1;i<=n;++i){
20         scanf("%d%d",&x,&y);
21         R=max(R,cal(x,y));
22         A=max(A,max(abs(x),abs(y)));
23     }
24     y=(int)(R*R*pi*10);
25     ans=y/10;
26     if(y%10>=5) ans++;
27     printf("%d\n",ans);
28     printf("%d\n",A*A*4);
29     return 0;
30 }

題3 架設電話線(phoneline)

技術分享
【 問題描述 】
Farmer John 打算將電話線引到自己的農場,但電信公司並不打算為他提供免費服務。
於是,FJ 必須為此向電信公司支付一定的費用。
FJ 的農場周圍分布著 N(1 <= N <= 1,000)根按 1..N 順次編號的廢棄的電話線桿,任意兩
根電話線桿間都沒有電話線相連。一共 P(1 <= P <= 10,000)對電話線桿間可以拉電話線,其
余的那些由於隔得太遠而無法被連接。
第 i 對電話線桿的兩個端點分別為 A_i、B_i,它們間的距離為 L_i (1 <= L_i <=
1,000,000)。數據中保證每對{A_i,B_i}最多只出現 1 次。編號為 1 的電話線桿已經接入了
全國的電話網絡,整個農場的電話線全都連到了編號為 N 的電話線桿上。也就是說,FJ 的
任務僅僅是找一條將 1 號和 N 號電話線桿連起來的路徑,其余的電話線桿並不一定要連入
電話網絡。
經過談判,電信公司最終同意免費為 FJ 連結 K(0 <= K < N)對由 FJ 指定的電話線桿。
對於此外的那些電話線,FJ 需要為它們付的費用,等於其中最長的電話線的長度(每根電
話線僅連結一對電話線桿)。如果需要連結的電話線桿不超過 K 對,那麽 FJ 的總支出為 0。
請你計算一下,FJ 最少需要在電話線上花多少錢。
【輸入格式】
* 第 1 行: 3 個用空格隔開的整數:N,P,以及 K
* 第 2..P+1 行: 第 i+1 行為 3 個用空格隔開的整數:A_i,B_i,L_i
【輸入樣例】phoneline.in
5 7 1
1 2 5
3 1 4
2 4 8
3 2 3
5 2 9
3 4 7
4 5 6
【輸入說明】
一共有 5 根廢棄的電話線桿。電話線桿 1 不能直接與電話線桿 45 相連。電話線桿 5
不能直接與電話線桿 13 相連。其余所有電話線桿間均可拉電話線。電信公司可以免費為
FJ 連結一對電話線桿。
【輸出格式】
* 第 1 行: 輸出 1 個整數,為 FJ 在這項工程上的最小支出。如果任務不可能完成,輸
出-1
【輸出樣例】phoneline.out
4
【輸出說明】
FJ 選擇如下的連結方案:1->33->22->5,這 3 對電話線桿間需要的電話線的長度分
別為 439。FJ 讓電信公司提供那條長度為 9 的電話線,於是,他所需要購買的電話線的
最大長度為 4
題目

tag:二分、最短路

思路:由於對於路徑的選擇、尋找答案都有很大的不確定性,可以考慮二分答案x作劃分免費和付費的分界線,它也是付費邊的上限,如果選擇的邊比x大視作距離為1,否則距離為0,那麽dis[n]就被賦予了新的意義——從點1到點n最少選擇的大於x的邊數,再看有沒有超過k。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 #define ll long long
 8 #define maxn 100010
 9 #define inf 1<<30
10 using namespace std;
11 int n,m,k,hl[1010],vis[1010],dis[1010],cnt,cs[20010];
12 queue<int>Q;
13 struct X{
14     int u,v,w,ne;
15 }e[20010];
16 void add(int u,int v,int w)
17 {
18     e[++cnt].u=u;
19     e[cnt].v=v;
20     e[cnt].w=w;
21     e[cnt].ne=hl[u];
22     hl[u]=cnt;
23 }
24 void spfa()
25 {
26     memset(dis,127/3,sizeof(dis));
27     dis[1]=0;
28     vis[1]=1;
29     Q.push(1);
30     while(!Q.empty()){
31         int u=Q.front();
32         Q.pop();
33         for(int i=hl[u];i;i=e[i].ne){
34             int v=e[i].v;
35             if(dis[v]>dis[u]+cs[i]){
36                 dis[v]=dis[u]+cs[i];
37                 if(!vis[v]){
38                     vis[v]=1;
39                     Q.push(v);
40                 }
41             }
42         }
43         vis[u]=0;
44     }
45 }
46 bool div2(int x)
47 {
48     memset(cs,0,sizeof(cs));
49     for(int i=1;i<=n;++i)
50         for(int j=hl[i];j;j=e[j].ne)
51             if(e[j].w>x) cs[j]=1;
52     spfa();
53     return dis[n]<=k;
54 }
55 bool cmp(int x,int y){
56     return x>y;
57 }
58 int main()
59 {
60     //freopen("phoneline.in","r",stdin);
61     //freopen("phoneline.out","w",stdout);
62     int x,y,w;
63     scanf("%d%d%d",&n,&m,&k);
64     for(int i=1;i<=m;++i){
65         scanf("%d%d%d",&x,&y,&w);
66         add(x,y,w);
67         add(y,x,w);
68     }
69     int l=0,r=1000001;
70     while(l<r){
71         int mid=(l+r)>>1;
72         if(div2(mid)) r=mid;
73         else l=mid+1;
74     }
75     r==1000001?printf("-1"):printf("%d\n",r);
76     return 0;
77 }

題4 洪水(slikar)

技術分享
【問題描述】
一天,一個畫家在森林裏寫生,突然爆發了山洪,他需要盡快返回住所中,那裏是安全
的。
森林的地圖由 R 行 C 列組成,空白區域用點“.”表示,洪水的區域用“*”表示,而
巖石用“X”表示,另畫家的住所用“D”表示,畫家用“S”表示。
有以下幾點需要說明:
1.每一分鐘畫家能向四個方向移動一格(上、下、左、右)
2.每一分鐘洪水能蔓延到四個方向的相鄰格子(空白區域)
3.洪水和畫家都不能通過巖石區域
4.畫家不能通過洪水區域(同時也不行,即畫家不能移到某個格子,該格子在畫家達到
的同時被洪水蔓延到了,這也是不允許的)
5. 洪水蔓不到畫家的住所。
給你森林的地圖,編寫程序輸出最少需要花費多長時間才能從開始的位置趕回家中。
【輸入】
輸入第一行包含兩個整數 R 和 C(R,C<=50)。
接下來 R 行每行包含 C 個字符(“.”、“*”、“X”、“D”或“S”)。地圖保證只有一個“D”
和一個“S”。
【輸出】
輸出畫家最快安全到達住所所需的時間,如果畫家不可能安全回家則輸出“KAKTUS”。
【輸入輸出樣例 1 】
slikar.in slikar.out
3 3
D.*
...
.S.

3
【輸入輸出樣例 2 】
slikar.in slikar.out
3 3
D.*
...
..S

KAKTUS
【輸入輸出樣例 3 】
slikar.in slikar.out
3 6
D...*.
.X.X..
....S.

6
題目

tag:模擬/dfs、bfs/最短路

思路:初始化所有點洪水出現的時間為無窮大,以每個“*”作基點向外dfs預處理更新時間(能取到最小值再擴展,此處算是剪枝),之後bfs走迷宮,到達的時間一定要先於洪水出現的時間,也可以二維轉一維跑SPFA。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 #define ll long long
 8 #define maxn 2510
 9 #define inf 707406378
10 using namespace std;
11 int dx[]={0,1,0,-1},dy[]={1,0,-1,0},n,m,cnt,dis[maxn],hl[maxn],MP[maxn],S,T,vis[maxn];
12 char mp[60][60];
13 queue<int>Q;
14 struct X{
15     int u,v,w,ne;
16 }e[maxn*4];
17 void add(int u,int v)
18 {
19     e[++cnt].u=u;
20     e[cnt].v=v;
21     e[cnt].ne=hl[u];
22     hl[u]=cnt;
23 }
24 int cal(int x,int y){return (x-1)*m+y;}
25 bool ok(int x,int y)
26 {
27     if(x>=1&&x<=n&&y>=1&&y<=m) return true;
28     return false;
29 }
30 void dfs(int x,int y,int t)
31 {
32     if(!t||(ok(x,y)&&mp[x][y]==.&&t<MP[cal(x,y)])){
33         MP[cal(x,y)]=t;
34         for(int i=0;i<4;++i) dfs(x+dx[i],y+dy[i],t+1);
35     }
36 }
37 bool spfa()
38 {
39     dis[S]=0;
40     vis[S]=1;
41     Q.push(S);
42     while(!Q.empty()){
43         int u=Q.front();
44         Q.pop();
45         for(int i=hl[u];i;i=e[i].ne){
46             int v=e[i].v,aft=dis[u]+1;
47             if(dis[v]>aft&&MP[v]>aft){
48                 dis[v]=aft;
49                 if(!vis[v]){
50                     vis[v]=1;
51                     Q.push(v);
52                 }
53             }
54         }
55         vis[u]=0;
56     }
57     if(dis[T]==inf) return false;
58     return true;
59 }
60 int main()
61 {
62     //freopen("slikar.in","r",stdin);
63     //freopen("slikar.out","w",stdout);
64     memset(dis,127/3,sizeof(dis));
65     memset(MP,127/3,sizeof(MP));
66     scanf("%d%d",&n,&m);
67     for(int i=1;i<=n;++i)
68         for(int j=1;j<=m;++j)
69             scanf(" %c",&mp[i][j]);
70     for(int i=1;i<=n;++i)
71         for(int j=1;j<=m;++j){
72             if(mp[i][j]==*) dfs(i,j,0);
73             else{
74                 switch(mp[i][j]){
75                     case S:S=cal(i,j);break;
76                     case D:T=cal(i,j);break;
77                     case X:continue;break;
78                 }
79                 for(int k=0;k<4;++k){
80                     int X=i+dx[k],Y=j+dy[k],t=1;
81                     if(ok(X,Y)&&mp[X][Y]!=*&&mp[X][Y]!=X) add(cal(i,j),cal(X,Y));
82                 }
83             }
84         }
85     if(!spfa()) puts("KAKTUS");
86     else printf("%d\n",dis[T]);
87     return 0;
88 }

————————今天好晚了懶得粘分割線呢————————

  芒果君:表示這次終於沒有翻車,沒有預計結果因為害怕這麽多模擬寫炸,最後還挺高的,開森,不過以後還是要多刷圖論啊。

技術分享

暑假第四次考試 沖刺Noip模擬賽4 解題報告——五十嵐芒果醬