2018/7/19 考試(tower,work,holes)
noip模擬賽,挺良心的題,考的賊爛(膜一下@來日方長大佬(sdfz rank1))
不多說了,看題吧
1.tower
題面:
鐵塔(tower.pas/c/cpp)
題目描述
Rainbow和Freda要在PoeticIsland市的一座山腳下蓋房子定居了......
蓋房子需要鋼材,幸運的是,這裏有排成一行的n座廢棄的鐵塔,從左到右編號為1~n,其中第i座的高度為h[i]。
Rainbow和Freda想蓋一座上面小下面大的城堡,並且城堡的層數盡可能多。
因此,他們要把這些鐵塔分成盡量多組,每組內的鐵塔編號必須是連續的,並且從左到右各組內鐵塔的高度之和單調不減。
最後,他們會用每組鐵塔所提供的鋼材構成一層城堡。
輸入格式:
第一行一個整數n。第二行n個整數,第i個整數表示h[i]。
輸出格式:
輸出一個整數,表示(n-最多能分成的組數)。
思路:
正解是DP,我手打了一個貪心,20分。。。。。
貪心可以被證明是錯的,(2,2,1,3,3,自己看一下),爆搜也會超時
怎麽辦呢?
DP
我們要求的其實就是將原序列劃分為多個子串
且每一個子串長度和連續不降
所以我們可以用前綴和預處理一下
然後開始DP
我們要保證在最後面的合起來的數盡可能的小
所以維護3個數組
dp數組,前綴和數組和最大值數組
線性轉移即可
代碼(感謝顏神):
#include<iostream> #include<cstdio> #include<cstring> #define int long long using namespace std; inline int get() { int n; char c; while((c=getchar())||1) { if(c>=‘0‘&&c<=‘9‘) { break; } } n=c-‘0‘; while((c=getchar())||1) { if(c>=‘0‘&&c<=‘9‘) { n=n*10+c-‘0‘; } else { return(n); } } } int dp[5001][5001]; int ints[5001],sums[5001]; inline int he(int l,int r) { if(l==0) { return(sums[r]); } return(sums[r]-sums[l-1]); } signed main() { // freopen("tower.in","r",stdin); // freopen("tower.out","w",stdout); memset(dp,128,sizeof(dp)); int n=get(); for(register int i=1;i<=n;i++) { ints[i]=get(); sums[i]=sums[i-1]+ints[i]; } for(register int i=1;i<=n;i++) { dp[i][1]=1; } for(register int j=2;j<=n;j++) { int mx=-1234567890,k=j; for(register int i=j;i<=n;i++) { while(k>1&&he(k-1,j-1)<=he(j,i)) { k--; mx=max(mx,dp[j-1][k]); } if(k<j) { dp[i][j]=mx+1; } } } int maxn=0; for(register int i=1;i<=n;i++) { maxn=max(maxn,dp[n][i]); } cout<<n-maxn<<endl; fclose(stdin); fclose(stdout); return(0); }
T2:work
題面:
工作計劃(work.pas/c/cpp)
題目描述:
Mark 在無意中了解到了Elf的身世。
在和James商量過之後,好心的他們打算送Elf返回故鄉。
然而,去往Gliese的飛船票價高的驚人,他們暫時還付不起這筆費用。
經過一番考慮,Mark打算去額外做一些工作來獲得收入。
經過一番調查,Mark發現有N個工作可以做。
做第i件工作所需要的時間為Di,同時也需要一個能力值Ci才可以去做。
每件工作都可以在任意時間開始,也可以做任意多次。
所有的工作給付的報酬都是一致的。
同時,有S個課程可以參加,我們認為今天是第0天,第i個課程在第Mi天開始,持續時間為Li天,課程結束之後能力值會變為Ai。
現在Mark 的能力值為1。
Mark 只能做工作到第T天(因為那是飛船起飛的日子)。
他想知道期限內他最多可以做多少件工作,好決定未來的打算。
於是他找到了applepi。でも、applepiは彼女と一緒に楽しむことが大切だ,(本人翻譯:但是applepi和他的女朋友在一起享受是很重要的)所以這個任務就交給你了。
輸入格式:
第一行包含三個空格分隔的整數T,S,N。
之後S 行,每行三個整數M,L,A,描述一個課程。
之後N 行,每行兩個整數C,D,描述一件工作。
輸出格式:
一個整數,表示Mark 最多可以做多少件工作。
思路:
標配DP,切了1個半小時
我們首先去重,確保每個能力值對應的是當前能力值能做到最大的工作效率(比如說能力都是3,一個要3天另一個要4天,我只存3天)
然後我們開始dp
dp數組我開兩維,一維代表時間,另一維代表能力
dp[i][j]表示在i這個位置,能力值為j時的最大收益
如果這個位置我們做工作,那麽我們工作結束時的最大收益就可以由當前+1轉移而來
如果這個位置我們學習,那麽我們到學習結束時的最大收益就是當前的最大收益
當然,我們一開始要將數組賦值為負無窮
這樣不可能的情況可以被自動排除
代碼:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define rii register int i #define rij register int j #define inf 1<<30 using namespace std; int gz[105]; struct kc{ int fi[105],nl[105],sl; }y[10005]; int n,t,s,dp[200005][105],mnl; int main() { // freopen("wrk.in","r",stdin); // freopen("wrk.out","w",stdout); scanf("%d%d%d",&t,&s,&n); for(rii=1;i<=s;i++) { int ltt,kkk,lzn; scanf("%d%d%d",<t,&kkk,&lzn); y[ltt].sl++; y[ltt].fi[y[ltt].sl]=kkk+ltt; y[ltt].nl[y[ltt].sl]=lzn; mnl=max(mnl,lzn); } for(rii=1;i<=105;i++) { gz[i]=inf; } for(rii=1;i<=n;i++) { int ltt,kkk; scanf("%d%d",<t,&kkk); gz[ltt]=min(gz[ltt],kkk); } int cnt=0; for(rii=0;i<=10000;i++) { for(rij=0;j<=100;j++) { dp[i][j]=-inf; } } dp[0][1]=0; for(rii=0;i<=t-1;i++) { int minx=inf; int maxn=0; for(rij=1;j<=mnl;j++) { if(i!=0) { dp[i][j]=max(dp[i][j],dp[i-1][j]); } minx=min(minx,gz[j]); if(minx==inf) { continue; } dp[i+minx][j]=max(dp[i+minx][j],dp[i][j]+1); maxn=max(maxn,dp[i][j]); } for(rij=1;j<=y[i].sl;j++) { dp[y[i].fi[j]][y[i].nl[j]]=max(dp[y[i].fi[j]][y[i].nl[j]],maxn); } } int ans=0; for(rii=1;i<=100;i++) { ans=max(dp[t][i],ans); } cout<<ans; return 0; }
3.holes
題面
樹洞(holes.pas/c/cpp)
題目描述
在一片棲息地上有N棵樹,每棵樹下住著一只兔子,有M條路徑連接這些樹。更特殊地是,只有一棵樹有3條或更多的路徑與它相連,其它的樹只有1條或2條路徑與其相連。
換句話講,這些樹和樹之間的路徑構成一張N個點、M條邊的無向連通圖,而度數大於2的點至多有1個。
近年以來,棲息地頻繁收到人類的侵擾。
兔子們聯合起來召開了一場會議,決定在其中K棵樹上建造樹洞。
當危險來臨時,每只兔子均會同時前往距離它最近的樹洞躲避,路程中花費的時間在數值上等於距離。
為了在最短的時間內讓所有兔子脫離危險,請你安排一種建造樹洞的方式,使最後一只到達樹洞的兔子所花費的時間盡量少。
輸入格式
第一行有3個整數N,M,K,分別表示樹(兔子)的個數、路徑數、計劃建造的樹洞數。
接下來M行每行三個整數x,y,表示第x棵樹和第y棵樹之間有一條路徑相連。1<=x,y<=N,x≠y,任意兩棵樹之間至多只有1條路徑。
輸出格式
一個整數,表示在最優方案下,最後一只到達樹洞的兔子所花費的時間。
思路:
一眼看出是一道樹上二分
發現只剩下30分鐘了,來不及寫
於是50pts暴力走人
怎麽二分呢?
我們知道他有k個樹洞
我們就可以枚舉長度
判斷此時是否成立即可
2018/7/19 考試(tower,work,holes)