NOIP2011 提高组 Day1
自測:8:27——11:51
實際得分:100+60+20=180
期望得分:100+60+40=200
T3讀錯題,失20
http://cogs.pro/cogs/page/page.php?aid=16
T1 鋪地毯
【問題描述】?
為了準備一個獨特的頒獎典禮,組織者在會場的一片矩形區域(可看做是平面直角坐標系的第一象限)鋪上一些矩形地毯。一共有 n張地毯,編號從 1 到n。現在將這些地毯按照編號從小到大的順序平行于坐標軸先后鋪設,后鋪的地毯覆蓋在前面已經鋪好的地毯之上。
地毯鋪設完成后,組織者想知道覆蓋地面某個點的最上面的那張地毯的編號。注意:在矩形地毯邊界和四個頂點上的點也算被地毯覆蓋。?
【輸入】?
輸入文件名為 carpet.in。?
輸入共 n+2行。?
第一行,一個整數 n,表示總共有 n張地毯。?
接下來的 n行中,第 i+1行表示編號 i的地毯的信息,包含四個正整數 a,b,g,k,每兩個整數之間用一個空格隔開,分別表示鋪設地毯的左下角的坐標(a,b)以及地毯在 x 軸和 y軸方向的長度。?
第 n+2 行包含兩個正整數 x 和 y,表示所求的地面的點的坐標(x,y) 。?
【輸出】?
輸出文件名為 carpet.out。?
輸出共 1 行,一個整數,表示所求的地毯的編號;若此處沒有被地毯覆蓋則輸出-1。?
【輸入輸出樣例 1】
carpet.in
3?
1 0 2 3?
0 2 3 3?
2 1 3 3?
2 2
carpet.out
3
【輸入輸出樣例說明】?
如下圖,1 號地毯用實線表示,2 號地毯用虛線表示,3 號用雙實線表示,覆蓋點(2,2)的最上面一張地毯是 3 號地毯。
?
【輸入輸出樣例 2】
carpet.in
3?
1 0 2 3?
0 2 3 3?
2 1 3 3?
4 5
carpet.out
-1
【輸入輸出樣例說明】?
如上圖,1 號地毯用實線表示,2 號地毯用虛線表示,3 號用雙實線表示,點(4,5)
沒有被地毯覆蓋,所以輸出-1。?
【數據范圍】?
對于 30%的數據,有 n≤2;?
對于 50%的數據,0≤a, b, g, k≤100;?
對于 100%的數據,有 0≤n≤10,000,0≤a, b, g, k≤100,000。
從后往前枚舉判斷
時間復雜度:O(n)
?
#include<cstdio> #define N 10001 using namespace std; int a,b,g,k,x,y,n; int x1[N],x2[N],y1[N],y2[N]; int main() {freopen("carpet.in","r",stdin);freopen("carpet.out","w",stdout);scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d%d%d%d",&a,&b,&g,&k);x1[i]=a;x2[i]=a+g;y1[i]=b;y2[i]=b+k;}scanf("%d%d",&x,&y);for(int i=n;i;i--){if(x>=x1[i]&&x<=x2[i]&&y>=y1[i]&&y<=y2[i]) {printf("%d",i);fclose(stdin); fclose(stdout);return 0;}}printf("-1");fclose(stdin);fclose(stdout);return 0; } View Code?
?
?
?
T2 選擇客棧
時間限制:1 s?? 內存限制:128 MB
【問題描述】
?
麗江河邊有n 家很有特色的客棧,客棧按照其位置順序從1 到n 編號。每家客棧都按照某一種色調進行裝飾(總共k 種,用整數0 ~ k-1 表示),且每家客棧都設有一家咖啡店,每家咖啡店均有各自的最低消費。
兩位游客一起去麗江旅游,他們喜歡相同的色調,又想嘗試兩個不同的客棧,因此決定分別住在色調相同的兩家客棧中。晚上,他們打算選擇一家咖啡店喝咖啡,要求咖啡店位于兩人住的兩家客棧之間(包括他們住的客棧),且咖啡店的最低消費不超過p。
他們想知道總共有多少種選擇住宿的方案,保證晚上可以找到一家最低消費不超過p元的咖啡店小聚。
?
【輸入】
輸入文件hotel.in,共n+1 行。
第一行三個整數n,k,p,每兩個整數之間用一個空格隔開,分別表示客棧的個數,色調的數目和能接受的最低消費的最高值;
接下來的n 行,第i+1 行兩個整數,之間用一個空格隔開,分別表示i 號客棧的裝飾色調和i 號客棧的咖啡店的最低消費。
?
【輸出】
輸出文件名為hotel.out。
?
輸出只有一行,一個整數,表示可選的住宿方案的總數。
?
【輸入輸出樣例1】
?
hotel.in
?
5 2 3
0 5
1 3
0 2
1 4
1 5
?
hotel.out
?
3
?
【輸入輸出樣例說明】
?
| 客棧編號 | ① | ② | ③ | ④ | ⑤ |
| 色調 | 0 | 1 | 0 | 1 | 1 |
| 最低消費 | 5 | 3 | 2 | 4 | 5 |
?
2 人要住同樣色調的客棧,所有可選的住宿方案包括:住客棧①③,②④,②⑤,④⑤,但是若選擇住4、5 號客棧的話,4、5 號客棧之間的咖啡店的最低消費是4,而兩人能承受的最低消費是3 元,所以不滿足要求。因此只有前3 種方案可選。
?
【數據范圍】
對于30%的數據,有n≤100;
對于50%的數據,有n≤1,000;
對于100%的數據,有2≤n≤200,000, 0≤K≤50,0≤P≤100, 0≤最低消費≤100, K≤50,0≤P≤100,
法一、O(nk+n)
same[i][j]表示前i個客棧中,色調為j的個數
pre[i]表示前i個客棧中,最后一個消費<=p的客棧
O(nk)預處理same[]
然后枚舉客棧i
如果pre[i]=i,說明客棧i的消費<=p,那么 i 與 i前面任意一個色調為color[i]的客棧 都是合法的
所以ans+=sum[i][color[i]]-1
如果pre[i]!=i,說明客棧i的消費>p,那么 i 與 pre[i]前面任意一個色調為color[i]的客棧(包括pre[i]) 都是合法的
所以ans+=sum[pre[i]][color[i]]
#include<cstdio> #define N 200001 using namespace std; int n,k,p; int same[N][51],sum[51],pre[N],last,co[N]; long long ans; int main() {freopen("hotel.in","r",stdin);freopen("hotel.out","w",stdout);scanf("%d%d%d",&n,&k,&p);int x,y;for(int i=1;i<=n;i++){scanf("%d%d",&x,&y);sum[x]++;co[i]=x;for(int j=0;j<=k;j++) same[i][j]=sum[j]; if(y<=p) last=i;pre[i]=last;}for(int i=1;i<=n;i++)if(pre[i]==i) ans+=same[i][co[i]]-1;else ans+=same[pre[i]][co[i]];printf("%lld",ans); } View Code法二、O(n)
last[i]=j 表示當前顏色為i的 所有客棧中,最后一個的是j
lastt 表示當前所有客棧中,最后一個消費<=p的客棧
sum_tot[i]=j ?表示當前顏色為i的客棧共有j個
sum[i]=j 表示當前與 顏色為i的這個客棧 可以組成的合法方案數
直接看代碼吧。。
#include<cstdio> #define N 200001 using namespace std; int n,k,p; int last[51],lastt,sum_tot[51],sum[51]; long long ans; int main() {freopen("hotel.in","r",stdin);freopen("hotel.out","w",stdout);scanf("%d%d%d",&n,&k,&p);int x,y;for(int i=1;i<=n;i++){scanf("%d%d",&x,&y);if(y<=p) lastt=i;if(last[x]<=lastt) sum[x]=sum_tot[x];sum_tot[x]++; last[x]=i;ans+=sum[x]; }printf("%lld",ans); } View Code自測時打的n2的暴力 60分
#include<cstdio> #include<algorithm> #define N 200001 using namespace std; int n,k,p; int sum[N]; long long ans,tmp; struct node {int id,color; }e[N]; int main() {freopen("hotel.in","r",stdin);freopen("hotel.out","w",stdout);scanf("%d%d%d",&n,&k,&p);int x;for(int i=1;i<=n;i++){e[i].id=i; scanf("%d",&e[i].color);scanf("%d",&x);sum[i]=sum[i-1]+(x<=p);}for(int i=1;i<n;i++)for(int j=i+1;j<=n;j++)if(e[i].color==e[j].color&&sum[e[j].id]-sum[e[i].id-1]) ans++;printf("%lld",ans); } View Code為什么沒想出來?
1、一開始讀錯題,看成了選的喝咖啡的地方不同也是不同的方案
不認真讀題,難道覺得自己可以輕松應對NOIP了嗎?
記住SDOI2017的教訓
2、開始想到的:
令f表示當前合法的方案總數,那么如果當前客棧的花費<=p,那么f中的每一種方案,拿出一個客棧都可與當前客棧形成新的方案
但這樣不對,比如1 2 ,1 3, 1 4, 2 3, 2 4,3 4 各拿出一個是1 1 1 2 2 ?3,總之有重復
然后就不繼續想了
下次思路出現問題不要棄療,改
?
T3 mayan游戲
時間限制:3 s?? 內存限制:128 MB
【問題描述】
Mayan puzzle 是最近流行起來的一個游戲。游戲界面是一個7 行5 列的棋盤,上面堆放著一些方塊,方塊不能懸空堆放,即方塊必須放在最下面一行,或者放在其他方塊之上。游戲通關是指在規定的步數內消除所有的方塊,消除方塊的規則如下:
1、 每步移動可以且僅可以沿橫向(即向左或向右)拖動某一方塊一格:當拖動這一方塊時,如果拖動后到達的位置(以下稱目標位置)也有方塊,那么這兩個方塊將交換位置(參見輸入輸出樣例說明中的圖6 到圖7);如果目標位置上沒有方塊,那么被拖動的方塊將從原來的豎列中抽出,并從目標位置上掉落(直到不懸空,參見下面圖1 和圖2);
2、 任一時刻,如果在一橫行或者豎列上有連續三個或者三個以上相同顏色的方塊,則它們將立即被消除(參見圖1 到圖3)。
注意:
a) 如果同時有多組方塊滿足消除條件,幾組方塊會同時被消除(例如下面圖4,三個顏色為1 的方塊和三個顏色為2 的方塊會同時被消除,最后剩下一個顏色為2 的方塊)。
b) 當出現行和列都滿足消除條件且行列共享某個方塊時,行和列上滿足消除條件的所有方塊會被同時消除(例如下面圖5 所示的情形,5 個方塊會同時被消除)。
3、 方塊消除之后,消除位置之上的方塊將掉落,掉落后可能會引起新的方塊消除。注意:掉落的過程中將不會有方塊的消除。
上面圖1 到圖3 給出了在棋盤上移動一塊方塊之后棋盤的變化。棋盤的左下角方塊的坐標為(0, 0),將位于(3, 3)的方塊向左移動之后,游戲界面從圖1 變成圖2 所示的狀態,此時在一豎列上有連續三塊顏色為4 的方塊,滿足消除條件,消除連續3 塊顏色為4 的方塊后,上方的顏色為3 的方塊掉落,形成圖3 所示的局面。
【輸入】
輸入文件mayan.in,共6 行。
第一行為一個正整數n,表示要求游戲通關的步數。
接下來的5 行,描述7*5 的游戲界面。每行若干個整數,每兩個整數之間用一個空格隔開,每行以一個0 結束,自下向上表示每豎列方塊的顏色編號(顏色不多于10 種,從1 開始順序編號,相同數字表示相同顏色)。
輸入數據保證初始棋盤中沒有可以消除的方塊。
【輸出】
輸出文件名為mayan.out。
如果有解決方案,輸出n 行,每行包含3 個整數x,y,g,表示一次移動,每兩個整數之間用一個空格隔開,其中(x,y)表示要移動的方塊的坐標,g 表示移動的方向,1 表示向右移動,-1 表示向左移動。注意:多組解時,按照x 為第一關健字,y 為第二關健字,1優先于-1,給出一組字典序最小的解。游戲界面左下角的坐標為(0,0)。
如果沒有解決方案,輸出一行,包含一個整數-1。
【輸入輸出樣例1】
mayan.in
3
1 0
2 1 0
2 3 4 0
3 1 0
2 4 3 4 0
mayan.out
2 1 1
3 1 1
3 0 1
【輸入輸出樣例說明】
按箭頭方向的順序分別為圖6 到圖11
樣例輸入的游戲局面如上面第一個圖片所示,依次移動的三步是:(2,1)處的方格向右移動,(3,1)處的方格向右移動,(3,0)處的方格向右移動,最后可以將棋盤上所有方塊消除。
【數據范圍】
對于30%的數據,初始棋盤上的方塊都在棋盤的最下面一行;
對于100%的數據,0 < n≤5。
?
模擬、dfs
貌似好像只有一個剪枝:
若當前有某種顏色的方塊數量為1或2,則reutrn
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int a[5][7],k[11],ans[6][4]; int n,tot[11]; bool ok; void clear(); void down()//可與消除形成連鎖反應的下降 {int sum;bool okk=false;for(int i=0;i<5;i++){sum=0;for(int j=0;j<7;j++){if(sum==k[i]) break;if(a[i][j]){sum++;continue;}else{int k=j;while(!a[i][k]) k++;swap(a[i][j],a[i][k]);sum++;okk=true;}}}if(okk) clear(); } void down2()//左移右移的下降,不消除 {int sum;for(int i=0;i<5;i++){sum=0;for(int j=0;j<7;j++){if(sum==k[i]) break;if(a[i][j]){sum++;continue;}else{int k=j;while(!a[i][k]) k++;swap(a[i][j],a[i][k]);sum++;}}} } void left_down(int x,int y)//左移 {swap(a[x][y],a[x-1][y]);k[x-1]++;k[x]--;down2(); } void right_down(int x,int y)//右移 {swap(a[x][y],a[x+1][y]);k[x+1]++;k[x]--;down2(); } void clear() {bool ok1,ok2,ok3=false;for(int i=0;i<5;i++)for(int j=0;j<k[i];j++){if(!a[i][j]) continue;ok1=ok2=false;int r=i+1,u=j+1;for(;r<5;r++) if(a[r][j]!=a[i][j]) break; r--;//橫著 for(;u<5;u++) if(a[i][u]!=a[i][j]) break; u--;//豎著 if(r-i+1>=3) ok1=true;if(u-j+1>=3) ok2=true;if(ok1){ok3=true;int down,up;for(int s=i;s<=r;s++) {for(down=j-1;down>=0;down--)//只有橫著的時候才有可能出現與豎著的共用的情況 if(a[s][j]!=a[s][down]) break;down++;for(up=j+1;up<7;up++)if(a[s][j]!=a[s][up]) break;up--;a[s][j]=0,k[s]--;if(up-down+1>=3) for(int t=down;t<=up;t++) if(a[s][t])a[s][t]=0,k[s]--;}}if(ok2){ok3=true;for(int t=j;t<=u;t++) if(a[i][t]){a[i][t]=0; k[i]--;}}}if(ok3) down();} bool empty() {for(int i=0;i<5;i++)for(int j=0;j<7;j++)if(a[i][j]) return false;return true; } bool check1()//若一種顏色的數量為1或2,則不合法 {memset(tot,0,sizeof(tot));for(int i=0;i<5;i++)for(int j=0;j<7;j++)tot[a[i][j]]++;for(int i=1;i<=10;i++) if(tot[i]==1||tot[i]==2) return false;return true; } void dfs(int now) {if(ok) return;if(now==n+1){if(empty()){for(int i=1;i<=n;i++)printf("%d %d %d\n",ans[i][1],ans[i][2],ans[i][3]);ok=true;}return;}if(!check1()) return;int b[5][7];int c[11];memcpy(b,a,sizeof b);memcpy(c,k,sizeof c);for(int i=0;i<5;i++)for(int j=0;j<k[i];j++){if(!a[i][j]) continue;if(i!=4&&a[i+1][j]&&a[i][j]!=a[i+1][j])//向右交換 {ans[now][3]=1;ans[now][1]=i;ans[now][2]=j;swap(a[i][j],a[i+1][j]);clear();dfs(now+1);memcpy(a,b,sizeof a);memcpy(k,c,sizeof k);}else if(i!=4&&a[i+1][j]==0&&a[i][j]!=a[i+1][j]) //向右移 {ans[now][3]=1;ans[now][1]=i;ans[now][2]=j;right_down(i,j);clear();dfs(now+1);memcpy(a,b,sizeof a);memcpy(k,c,sizeof k);}if(i==4&&a[i-1][j]&&a[i][j]!=a[i-1][j])//向左交換 {ans[now][3]=-1;ans[now][1]=i;ans[now][2]=j;swap(a[i][j],a[i-1][j]);clear();dfs(now+1);memcpy(a,b,sizeof a);memcpy(k,c,sizeof k);} else if(i&&a[i-1][j]==0&&a[i-1][j]!=a[i][j]) //向左移 {ans[now][3]=-1;ans[now][1]=i;ans[now][2]=j;left_down(i,j);clear();dfs(now+1);memcpy(a,b,sizeof a);memcpy(k,c,sizeof k);}} } int main() {/*freopen("mayan.in","r",stdin);freopen("mayan.out","w",stdout);*/scanf("%d",&n);int x,j;for(int i=0;i<5;i++){j=0;while(1){scanf("%d",&x);if(!x) {k[i]=j;//橫坐標為i的方塊數量 break;}a[i][j]=x;j++;} }dfs(1);if(!ok) printf("-1");return 0; } View Code輸出先輸出坐標,在輸出移動方向
不看好題,先輸出了方向
轉載于:https://www.cnblogs.com/TheRoadToTheGold/p/6693781.html
總結
以上是生活随笔為你收集整理的NOIP2011 提高组 Day1的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: git的一些常用操作
- 下一篇: Maven打包详细流程