T1:MHM
LGL今天一共要上n节课,这n节课由0标号至n。由于过度劳累,除了第0节课和第n节课,LGL还打算睡上m节课,所以他做了一个睡觉计划表。通过小道消息,LGL得知WQ今天会在学校中检查,所以他想少睡k节课。但是由于某些原因,他又想使相邻的两节睡觉的课之间上的课数量的最小值最大。由于他很困,所以他请你来帮他计算这个值。
输入格式:
第一行为三个整数 n、m、k,接下来的m行为m个整数ai,表示睡觉计划表中LGL想要睡觉的课。
输出格式:
一个整数,表示题目所求的值。
样例输入 |
样例输出 |
25 5 2 14 11 17 2 21 |
3 |
样例解释:
选择第2节和第14节不睡觉,这样子相邻的两节睡觉的课之间上的课数量的最小值为3,即第17节和第21节之间和第21节到第25节之间。没有答案更大的删除方案。
数据范围:
对于100%的数据:1<=n<=109,1<=k<=m<=50000,0<ai<n。
solution:
看题目了半天,这难道不是noip2015的跳石头的几乎是原题的变形吗。二分答案判定,废话不多说,直接上代码:
1 #include<cstdio> 2 int l,n,m,a[50005],L; 3 int check(int x) { 4 int last=0,ans=0; 5 for(int i=1;i<=n;i++){ 6 if(a[i]-last<x) ans++; 7 else last = a[i]; 8 } 9 if(ans>m)return 0; 10 return 1; 11 } 12 int main(){ 13 scanf("%d%d%d",&L,&n,&m); 14 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 15 a[n+1]=L; n++; 16 int l=0,r=L; 17 while(l<=r) { 18 int mid=(l+r)/2; 19 if(check(mid)) l=mid+1; 20 else r=mid-1; 21 } 22 printf("%d\n",l); 23 }
T2:AAFA
YYH有n道题要做。每一道题都有一个截止日期t,只要在该日期之前做完,他的父亲LRB就会奖励他w元钱。令人惊讶的是,每一道题他都只需要1秒来做。请问他最多能从父亲那里拿到多少钱?
输入格式:
第一行为一个整数 n,接下来的n行每一行都有两个数ti和wi,分别表示第i题的截止日期和奖励。
输出格式:
一个整数,表示YYH的最大获利。
样例输入 |
样例输出 |
3 2 10 1 5 1 7 |
17 |
样例解释:
第1秒做第3道题,第2秒做第1道题。
数据范围:
对于 100%的数据:1<=n、ti 、wi <=100000。
solution:
按截止时间排序从头往后选。选到第i个时,若已选择的题目数量小于ti,则该时间选择它一定更优;若已选择的数量等于ti,则比较第i题的收益和已选择的题目中的最小收益,在酌情选择。我没用队列维护这题10分。。。
#include <cstdio> #include <algorithm> #include <queue> typedef long long ll; struct work { ll d,p; }w[100001]; std::priority_queue<int,std::vector<int>,std::greater<int> > q; int n; ll sz,ans; bool comp(work a,work b) { return a.d<b.d; } int main() { freopen("aafa.in","r",stdin); freopen("aafa.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%I64d%I64d",&w[i].d,&w[i].p); std::sort(w+1,w+1+n,comp); ans=0; for(int i=1;i<=n;i++) { sz=q.size(); if(sz<w[i].d) q.push(w[i].p); else if(sz==w[i].d) { if(q.top()<w[i].p) { q.pop(); q.push(w[i].p); } } } ans=0; while(!q.empty()) { ans+=q.top(); q.pop(); } printf("%I64d",ans); return 0; }
T3:ZZI
YYH拿到了父亲给的钱欣喜若狂,把这些钱拿来造了n栋房子。现在他要给这些房子通电。他有两种方法:第一种是在房间里搭核电发电机发电,对于不同的房子,他需要花不同的代价Vi;,第二种是将有电的房子i的电通过电线通到没电的房子j中,这样子他需要花的代价为aij。他现在请你帮他算出他最少要花多少钱才能让所有的房子通上电。
输入格式:
第一行为一个整数 n。接下来的n行为 n 个整数vi,再接下来的n行每行n个数,第i行第j列的数表示aij。
输出格式:
一个整数,表示最小代价。
样例输入 |
样例输出 |
4 5 4 4 3 0 2 2 2 2 0 3 3 2 3 0 4 2 3 4 0 |
9 |
样例解释:
在第4栋房子造核电发电机,再将其他三栋房子通过电线连向它。
数据范围:
对于 100%的数据:1<=n<=300,1<=vi,aij<=100000,保证aii=0,aij=aji。
solution:
几乎裸最小生成树,prim算法,具体参考[USACO Oct08] 挖水井 。
#include<iostream> #include<cstdio> using namespace std; int n,dis[305],e[305][305],t,w,ans; bool flag; int main(){ freopen("zzi.in","r",stdin); freopen("zzi.out","w",stdout); scanf("%d",&n); dis[0]=(1<<30); for(int i=1;i<=n;i++){ scanf("%d",&dis[i]); if(dis[i]<dis[0]){ dis[0]=dis[i]; t=i; } } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ scanf("%d",&e[i][j]); } } ans+=dis[0]; dis[t]=0; for(int j=1;j<=n;j++){ if(dis[j]>e[t][j]){ dis[j]=e[t][j]; } } for(int i=1;i<=n-1;i++){ w=(1<<30); for(int j=1;j<=n;j++){ if(dis[j]<w&&dis[j]!=0){ w=dis[j]; t=j; } } ans+=w; dis[t]=0; for(int j=1;j<=n;j++){ if(dis[j]>e[t][j]){ dis[j]=e[t][j]; } } } printf("%d\n",ans); return 0; }