2017 09 17 測驗解題報告
預計分數 100+100+20 >=220
實際分數 100+50+20 =170
T1 :100
巧克力棒(chocolate)
Time Limit:1000ms Memory Limit:64MB
題目描述
LYK 找到了一根巧克力棒,但是這根巧克力棒太長了,LYK 無法一口吞進去。
具體地,這根巧克力棒長為 n,它想將這根巧克力棒折成 n 段長為 1 的巧克力棒,然後
慢慢享用。
它打算每次將一根長為 k 的巧克力棒折成兩段長為 a 和 b 的巧克力棒,此時若 a=b,則
LYK 覺得它完成了一件非常困難的事,並會得到 1 點成就感。
LYK 想知道一根長度為 n 的巧克力棒能使它得到最多幾點成就感。
第一行一個數 n。
輸出格式(chocolate.out)
一個數表示答案。
輸入樣例
7
輸出樣例
4
數據範圍
對於 20%的數據 n<=5。
對於 50%的數據 n<=20。
對於 80%的數據 n<=2000。
對於 100%的數據 n<=1000000000。
樣例解釋
將 7 掰成 3+4, 將 3 掰成 1+2, 將 4 掰成 2+2 獲得 1 點成就感, 將剩下的所有 2 掰成 1+1
獲得 3 點成就感。總共 4 點成就感。
把一段長度為n的(n為2的冪次方)巧克力二分可以切n-1次,每次用二的冪次方數對區間進行切割,
遞歸到長度為1或0(此時無法再切)統計長度
#include<cstdio> int n; int dfs(int sum) { if(sum==1||sum==0)return 0; int cnt=1; while(cnt*2<=sum) cnt*=2; return cnt-1+dfs(sum-cnt); } int main(){ freopen("chocolate.in","r",stdin); freopen("chocolate.out","w",stdout); scanf("%d",&n); printf("%d\n",dfs(n)); return 0; }
T2 :50
錯因:隊列數組開小應為1000*1000,實為1000
LYK 快跑!(run)
Time Limit:5000ms Memory Limit:64MB
題目描述
LYK 陷進了一個迷宮! 這個迷宮是網格圖形狀的。 LYK 一開始在(1,1)位置, 出口在(n,m)。
而且這個迷宮裏有很多怪獸,若第 a 行第 b 列有一個怪獸,且此時 LYK 處於第 c 行 d 列,此
時這個怪獸對它的威脅程度為|a-c|+|b-d|。
LYK 想找到一條路徑,使得它能從(1,1)到達(n,m),且在途中對它威脅程度最小的怪獸的
威脅程度盡可能大。
當然若起點或者終點處有怪獸時,無論路徑長什麽樣,威脅程度最小的怪獸始終=0。
輸入格式(run.in)
第一行兩個數 n,m。
接下來 n 行,每行 m 個數,如果該數為 0,則表示該位置沒有怪獸,否則存在怪獸。
數據保證至少存在一個怪獸。
輸入格式(run.out)
一個數表示答案。
輸入樣例
3 4
0 1 1 0
0 0 0 0
1 1 1 0
輸出樣例
1
數據範圍
對於 20%的數據 n=1。
對於 40%的數據 n<=2。
對於 60%的數據 n,m<=10。
對於 80%的數據 n,m<=100。
對於 90%的數據 n,m<=1000。
對於另外 10%的數據 n,m<=1000 且怪獸數量<=100。
bfs處理出每個點與距離最近怪獸的距離,二分答案,二分路徑上的最小值用bfs進行檢驗
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int maxn = 1003; int que[maxn*maxn][2],cnt=0; int map[maxn][maxn]; int dis[maxn][maxn]; struct Node{ int x,y; }node[400]; int fs[5]={1,0,-1,0,1}; int n,m; void bfs() { int head=0,tail=cnt; while(head<=tail) { int x=que[++head][0],y=que[head][1]; for(int i=0;i<4;i++) { int xx=x+fs[i],xy=y+fs[i+1]; if(xx>=1&&xx<=n&&xy>=1&&xy<=m&&!map[xx][xy]&&!dis[xx][xy]) { dis[xx][xy]=dis[x][y]+1; que[++tail][0]=xx,que[tail][1]=xy; } } } } bool vis[maxn][maxn]; bool judge(int ans) { int head=0,tail=1; memset(que,0,sizeof que); memset(vis,0,sizeof vis); que[1][0]=1,que[1][1]=1,vis[1][1]=1; while(head<tail) { int x=que[++head][0],y=que[head][1]; for(int i=0;i<4;i++) { int xx=x+fs[i],xy=y+fs[i+1]; if(xx>=1&&xx<=n&&xy>=1&&xy<=m&&dis[xx][xy]>=ans&&!map[xx][xy]&&!vis[xx][xy]) { if(xx==n&&xy==m)return true; que[++tail][0]=xx,que[tail][1]=xy;vis[xx][xy]=1; } } } return false; } int main() { freopen("run.in","r",stdin); freopen("run.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ scanf("%d",&map[i][j]); if(map[i][j]==1)que[++cnt][0]=i,que[cnt][1]=j; } if(map[1][1]||map[n][m]){ puts("0");return 0; } bfs(); int l=0,r=1000006; int ans; while(l<=r) { int mid=(l+r)/2; if(judge(mid)) { l=mid+1; ans=mid; } else r=mid-1; } printf("%d\n",ans); return 0; }
T3 : 20
錯因 不會....tarjan+亂搞
仙人掌(cactus)
Time Limit:1000ms Memory Limit:64MB
題目描述
LYK 在沖刺清華集訓(THUSC) !於是它開始研究仙人掌?,它想來和你一起分享它最近
研究的結果。
如果在一個無向連通圖中任意一條邊至多屬於一個簡單環 (簡單環的定義為每個點至多
經過一次) ,且不存在自環,我們稱這個圖為仙人掌。
LYK 覺得仙人掌還是太簡單了,於是它定義了屬於自己的仙人掌。
定義一張圖為美妙的仙人掌, 當且僅當這張圖是一個仙人掌且對於任意兩個不同的點 i,j,
存在一條從 i 出發到 j 的路徑,且經過的點的個數為|j-i|+1 個。
給定一張 n 個點 m 條邊且沒有自環的圖,LYK 想知道美妙的仙人掌最多有多少條邊。
數據保證整張圖至少存在一個美妙的仙人掌。
輸入格式(cactus.in)
第一行兩個數 n,m 表示這張圖的點數和邊數。
接下來 m 行,每行兩個數 u,v 表示存在一條連接 u,v 的無向邊。
輸出格式(cactus.out)
一個數表示答案
輸入樣例
4 6
1 2
1 3
1 4
2 3
2 4
3 4
輸出樣例
4
樣例解釋
選擇邊 1-2,1-3,2-3,3-4,能組成美妙的仙人掌,且不存在其它美妙仙人掌有超過 4 條
邊。
數據範圍
對於 20%的數據 n<=3。
對於 40%的數據 n<=5。
對於 60%的數據 n<=8。
對於 80%的數據 n<=1000。
對於 100%的數據 n<=100000 且 m<=min(200000,n*(n-1)/2)。
對於i和i+1點要過2個點,即只能為這兩個點之間直接有一條邊,那麽這n-1條連接i和i+1的邊一定選,選完這些邊之後正好滿足
要在保證仙人掌的前提下多選邊
保證邊沒有交集因為現在已經選了i到i+1的邊其他的邊會和現在已經選的邊形成環,否則,兩個邊有交集,不滿足仙人掌的性質,所以問題轉化成了線段覆蓋
#include<cstdio> #include<algorithm> using namespace std; const int maxn =200010; int n,m,cnt,ans; struct Edge{ int x,y; bool operator < (const Edge &x)const{ return y<x.y; } }edge[maxn*2]; int main() { freopen("cactus.in","r",stdin); freopen("cactus.out","w",stdout); scanf("%d%d",&n,&m); for(int a,b,i=1;i<=m;i++) { scanf("%d%d",&a,&b); if(a>b)swap(a,b); if(a!=b-1)edge[++cnt].x=a,edge[cnt].y=b; } sort(edge+1,edge+cnt+1); int tail=-1; for(int i=1;i<=cnt;i++) { if(edge[i].x>=tail) { tail=edge[i].y; ans++; } } printf("%d\n",ans+n-1); return 0; }
2017 09 17 測驗解題報告