codeforces VK Cup Round 1 (online mirror)
2015-04-06 15:31:25
总结:以前做的一场,题目难度无序... 虽然时间有点久了,但是有道题必须得补!
比赛时只做了一题(E题),而且是队友提醒的... 算是道折半搜索吧
刚刚补了B题,一道贪心题,比赛时做出来被hack了,后来过了之后又被FST... 真是够糗的。
B题:
其实就是一道贪心题... 枚举矩形的高度,然后求出在该高度下矩形的最小宽度,枚举所有可能高度后取最优解即可。
思路很明显... (比赛时脑子实在是混... QAQ),对于当前枚举的高度,我们先扫描一遍必须“躺下”的人,并让他们躺下,如果
必须躺下的人数大于n/2,显然该高度不符合。然后我们考虑剩下的人,如果躺下能使总宽度变小那么这个人的 w > h,躺下可以
使宽度减少 w - h,那么我们对这些人按照(w-h)降序排序,尽量使他们躺下即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=0;i<(n);++i) 17 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 18 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 19 #define MP(a,b) make_pair(a,b) 20 21 typedef long long ll; 22 typedef pair<int,int> pii; 23 const int INF = (1 << 30) - 1; 24 25 int n; 26 27 struct node{ 28 int w,h; 29 }nd[1010]; 30 31 bool cmp(node a,node b){ 32 return (a.w - a.h) > (b.w - b.h); 33 } 34 35 int main(){ 36 scanf("%d",&n); 37 for(int i = 1; i <= n; ++i){ 38 scanf("%d%d",&nd[i].w,&nd[i].h); 39 } 40 sort(nd + 1,nd + n + 1,cmp); 41 int ans = INF; 42 for(int h = 1; h <= 1000; ++h){ 43 int cnt = 0,sum = 0; 44 bool flag = true; 45 for(int i = 1; i <= n; ++i) if(nd[i].h >= nd[i].w){ //high person 46 if(nd[i].h > h){ 47 if(nd[i].w <= h && cnt < n / 2){ 48 cnt++; 49 sum += nd[i].h; 50 } 51 else{ 52 flag = false; 53 break; 54 } 55 } 56 else sum += nd[i].w; 57 } 58 if(flag == false) continue; 59 for(int i = 1; i <= n; ++i) if(nd[i].w > nd[i].h){ //wide person 60 if(nd[i].h > h){ 61 flag = false; 62 break; 63 } 64 if(nd[i].w <= h && cnt < n / 2){ 65 cnt++; 66 sum += nd[i].h; 67 } 68 else sum += nd[i].w; 69 } 70 if(flag) ans = min(ans,sum * h); 71 } 72 printf("%d\n",ans); 73 return 0; 74 }
E题:
由于最多取两种,总共最多取k张(k<=20),那么不妨先取一种,取0~k张,放进map数组中,比如价值为 v 的取了 i 张,
那么 map[v * i] = i。对于每种查询,我们只要枚举取不取第二种,如果取第二种那么取多少张,比如查询为 q,枚举第二种
价值为 v2,取了 i2 张,我们只要找 map[q - v2 * i2] 是否存在即可,如果存在,那么记录 i2 + map[q - v2 * i2] 为当前总张数,最后取最少的总张数。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cmath> 5 #include <vector> 6 #include <map> 7 #include <set> 8 #include <stack> 9 #include <queue> 10 #include <string> 11 #include <iostream> 12 #include <algorithm> 13 using namespace std; 14 15 #define MEM(a,b) memset(a,b,sizeof(a)) 16 #define REP(i,n) for(int i=1;i<=(n);++i) 17 #define REV(i,n) for(int i=(n);i>=1;--i) 18 #define FOR(i,a,b) for(int i=(a);i<=(b);++i) 19 #define RFOR(i,a,b) for(int i=(a);i>=(b);--i) 20 #define getmid(l,r) ((l) + ((r) - (l)) / 2) 21 #define MP(a,b) make_pair(a,b) 22 23 typedef long long ll; 24 typedef pair<int,int> pii; 25 const int INF = (1 << 30) - 1; 26 27 int n,k,q,x; 28 int v[5010]; 29 map<int,int> mp; 30 31 int main(){ 32 scanf("%d%d",&n,&k); 33 REP(i,n){ 34 scanf("%d",&v[i]); 35 for(int j = 1; j <= k; ++j) 36 mp[v[i] * j] = j; 37 } 38 scanf("%d",&q); 39 REP(i,q){ 40 int ans = INF,sum = 0; 41 scanf("%d",&x); 42 REP(j,n){ 43 for(int o = 0; o <= k; ++o){ 44 if(x - o * v[j] < 0) break; 45 if(mp[x - o * v[j]]){ 46 ans = min(ans,o + mp[x - o * v[j]]); 47 } 48 } 49 } 50 if(ans > k) printf("-1\n"); 51 else printf("%d\n",ans); 52 } 53 return 0; 54 }