G. Car Repair Shop
题目链接:http://codeforces.com/contest/730/problem/G
题意:
修车店提前问好n位顾客想要送车的时间Si和修车辆车的时间Ki,然后修车店安排时间,对于第i辆车如果【Si,Si+Ki-1】这段时间是有空的修车,如果没空则找到第一天满足【Ti,Ti+Ki-1】这段时间有空,安排修车,注意Ti可以<Si。输出每辆车修车的时间。
3
9 2
7 3
2 4
9 10
1 3
4 7
4
1000000000 1000000
1000000000 1000000
100000000 1000000
1000000000 1000000
1000000000 1000999999
1 1000000
100000000 100999999
1000001 2000000
分析:
在比赛想复杂了,结果错了。正确的思维使用数组l和数组r维护1-n辆车对用的修车时间。输入的起始时间为x,持续时间为y。l[0]和r[0]都置为0.l[0]和r[0]用在当前时间如果已经安排了修车的话,从l[0]+1时刻开始找合适的时间安排
对于来修的车,如果他与之前的没有冲突,直接用这段时间修车,即l[i]=x,r[i]=x+y-1。如果有冲突,让l[i]=r[j]+1,r[i]=l[i]+y-1;判断这段时间与之前的时候有冲突,没冲突就选这段时间。j从0-i循环。
代码:
#include <bits/stdc++.h> using namespace std; const int MAXN = 1111; int l[MAXN], r[MAXN], n, cnt; //用于检验当前时间是否与之前安排好的时间冲突,没冲突返回true inline bool check(int x, int y) { for (int i = 1; i <= cnt; ++i) if (!(x > r[i] || y < l[i])) return false; return true; } int main() { scanf("%d", &n); cnt = 0; for (int i = 1; i <= n; ++i) { int x, y; cin >> x >> y; if (check(x, x + y - 1)) { l[++cnt] = x; r[cnt] = x + y - 1; } else { for (int j = 0; j <= cnt; ++j) { if (check(r[j] + 1, r[j] + y)) { l[++cnt] = r[j] + 1; r[cnt] = r[j] + y; break; } } } cout << l[i] << " " << r[i] << endl; //用于维持l数组从小到大。 for (int j = 1; j < cnt; ++j) for (int k = j + 1; k <= cnt; ++k) if (l[j] > l[k]) swap(l[j], l[k]), swap(r[j], r[k]); } }
B题:Minimum and Maximum
题目链接:http://codeforces.com/contest/730/problem/B
题意:
其实就是个模拟人机询问,给定一个数组A,你不知道其内容,然后你输出“? x y”代表向电脑询问A[x]和A[y]的关系,电脑输入>,<,=表示其关系,但要求输入的询问个数不能超过[3*n/2]-2个。最后用“! min max”代表输出结果,输出数组中第几个数是最小值,第几个数是最大值。
分析:
做法就是模拟归并,对于每个数组询问i*2和i*2+1的关系,将大的值放入一个集合,小的放入另一个,这样询问n/2次。如果n为奇数的话,把最后一个放入这两个集合。然后分别对每个集合询问,这个直接就询问一遍问出对应的最大值或最小值就好了。结果我们错在输出的内容没有没有从缓冲区调出,也是醉了。
#include <bits/stdc++.h> std::vector<int> up, down; int query(int i, int j) { if (i == j) return 0; printf("? %d %d ", i + 1, j + 1); fflush(stdout);//这句话必须加,作用是立刻将printf的内容输出,不加这句话printf会先将输出内容存放到缓冲区,然后等时间片轮转到输出程序时在输出 char ans[3]; scanf("%s", ans); if (ans[0] == '<') return -1; else if (ans[0] == '=') return 0; else return 1; } int main() { int T; scanf("%d", &T); for (; T --; ) { int n; scanf("%d", &n); up.clear(); down.clear(); for (int i = 0; i < n / 2; ++ i) { if (query(i * 2, i * 2 + 1) < 0) { up.push_back(i * 2 + 1); down.push_back(i * 2); } else { down.push_back(i * 2 + 1); up.push_back(i * 2); } } if (n % 2 != 0) { up.push_back(n - 1); down.push_back(n - 1); } int maxindex = up[0], minindex = down[0]; for (int i = 1; i < (int)up.size(); ++ i) { if (query(up[i], maxindex) > 0) maxindex = up[i]; } for (int i = 1; i < (int)down.size(); ++ i) { if (query(down[i], minindex) < 0) minindex = down[i]; } printf("! %d %d ", minindex + 1, maxindex + 1); fflush(stdout); } }
J题:Bottles
题目链接:http://codeforces.com/contest/730/problem/J
题意:
给出每个瓶子现在装得水的体积,然后给出每个瓶子的体积,然后瓶子之间可以互相倒水,每倒出一体积水花费为1,然后问最少用几个瓶子装这些水,然后最少花费是多少。
分析:最少用几个桶很简单能求出来。然后背包出这些桶花费最少,比赛时简直智障,一直想贪心,都没往背包上想。
#include <bits/stdc++.h> using namespace std; struct qwe { int a,b; } e[110]; int cmp(qwe x,qwe y) { return (x.b>y.b || (x.b==y.b && x.a>y.a));//体积大的排序,如果体积相同就按照已经有水多的的在前面 } int cmp1(qwe x,qwe y)//按照体积小的排序 { return (x.b<y.b); } int dp[110][10010],s[110]; int main() { //freopen("C:\Users\acer\Desktop\in.txt","r",stdin); int n; scanf("%d",&n); int sum=0;//总共有多少水 for(int i=1;i<=n;i++) scanf("%d",&e[i].a),sum+=e[i].a; for(int i=1;i<=n;i++) scanf("%d",&e[i].b); sort(e+1,e+1+n,cmp); int t=0,q=0; int ans; for(int i=1;i<=n;i++) { t+=e[i].b; if(t>=sum) { ans=i; break; } }//找出最少的桶数 sort(e+1,e+1+n,cmp1); for(int i=1;i<=n;i++) s[i]=s[i-1]+e[i].b; memset(dp,0xBf,sizeof(dp)); dp[0][0]=0;//dp[j][k]表示j个桶,最多装多少水 for(int i=1;i<=n;i++)//用多少桶 { for(int j=min(i,ans);j>0;j--) for (int k=s[i];k>=e[i].b;k--) { dp[j][k]=max(dp[j][k],dp[j-1][k-e[i].b]+e[i].a); } } int fin=0; for (int k=s[n];k>=sum;k--) fin=max(fin,dp[ans][k]); printf("%d %d ",ans,sum-fin); return 0; }