A - Snacktower
CodeForces - 767A
题意:从第一个数开始看,如果这个数是最大的,那么就输出这个数然后再往前找,如果前面的是比他小一的继续输入,如果不符合条件就输出空行,
题解:水过
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #define INF 0x3f3f3f3f #define lowbit(x) (x&(-x)) using namespace std; typedef long long ll; const int maxn = 1e5 + 10; int a[maxn]; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { int x; scanf("%d",&x); a[x] = i; } int pos = n; for(int i = 1; i <= n;i++) { if(pos == 0) break; while(true) { if(pos == 0) break; if(a[pos] <= i) { printf("%d ",pos); pos--; } else break; } printf(" "); } }
B - The Queue
CodeForces - 767B
题意:一个人想去办理事情,想等待最少的时间去办理,现在他知道当天办公室的开门时间和工作人员对于每个人的接待时间(都是t)和他们的工作时间,然后他还知道当天去办理业务的每个人的到达时间,如果他和其他人在同时到达那里的话,他需要排在最后去办理,还有就是工作人员在剩余工作时间不足以完成一个人的业务办理的时候,他不会给新来的人办理业务。(他可以在零点到,办公室在零点后ts时开门,tf时关门,可以提前到,按到的先后排队)
题解:贪心 + 模拟
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #define INF 0x3f3f3f3f #define lowbit(x) (x&(-x)) using namespace std; typedef long long ll; const int maxn = 1e5 + 10; ll m = 1e12 + 10; ll k,n,ts,tf,t,ans; int main() { scanf("%lld %lld %lld", &ts, &tf, &t); scanf("%lld", &n); while (n--) { scanf("%lld",&k); if(k <= tf - t) { if(k && max(ts,k - 1) <= tf - t && ts - k + 1 < m) { m = ts - k + 1; ans = min(ts,k - 1); } ts = max(ts,k) + t; } } if(ts <= tf - t) ans = ts; printf("%lld ",ans); }
C - Garland
CodeForces - 767C
题意:有一棵树,每个节点都有一个权值,需要分成相等的三部分,能则输出剪下的结点否则输出-1(不能剪下根节点)
题解:先判断所有的值总和是不是 3 的倍数,如果不是的话直接输出 -1,如果是的话,就从根节点开始跑dfs累加权值,当权值跑到为总值的1/3时就记录下顶点值。最后判断记录下来的顶点的个数是不是2个,如果是两个的话就刚好把一颗树割成了三部分
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #define INF 0x3f3f3f3f #define lowbit(x) (x&(-x)) using namespace std; typedef long long ll; const int maxn = 1e6 + 10; int n; vector<int>g[maxn]; int tmp,num,root; int val[maxn]; ll sum[maxn]; int ans[3]; void dfs(int now) { sum[now] = val[now]; for(int i = 0; i < g[now].size(); i++) { int v = g[now][i]; dfs(v); sum[now] += sum[v]; } if(root != now && sum[now] == tmp && num < 2) { ans[num++] = now; sum[now] = 0; } } int main() { scanf("%d",&n); tmp = num = 0; for(int i = 1; i <= n; i++) { int u; scanf("%d %d",&u,&val[i]); tmp += val[i]; if(u == 0) { root = i; continue; } g[u].push_back(i); } if(tmp % 3 != 0) { printf("-1 "); } else { tmp /= 3; dfs(root); if(num == 2) printf("%d %d ",ans[0],ans[1]); else printf("-1 "); } }
D - Cartons of milk
CodeForces - 767D
题意:一个人一天要喝k瓶牛奶,如果冰箱里的牛奶不够k瓶就全部喝完,目前冰箱里有n瓶牛奶,给出每瓶牛奶的保质期,即还有几天会过期,过期的牛奶要被扔掉,再给出商店中m瓶牛奶的保质期,问是否存在一种方案使得这个人不扔掉任何一瓶牛奶,如果有,他最多可以从商店买多少瓶牛奶
题解:貌似可以二分答案加贪心的方法做,但也可以直接贪心做。商店的牛奶按照保质期的时间排序之后,将原来有的牛奶进行处理,a[i] 表示第 i 天还是可以喝的牛奶有a[i] 瓶。然后从1e7开始遍历,如果第i天,a[i] > k的话,说明原来有多的牛奶只能在之前的时间里把它喝掉,那么就将a[i] - k的牛奶放在a[i - 1]中。如果a[i] <= k 的话说明第i天还是可以喝剩余的牛奶的,那么就去商店里去找保质期大雨等于i的就可以了,直到这一天喝的牛奶数量到达k杯就停止,之后在向前遍历。当遍历到a[0]的时候,如果a[0] > k的话说明喝不完就可以直接输出-1了,否则就再次在商店里找有没有可以喝的牛奶。之后vector输出即可
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<vector> #include<string.h> using namespace std; #define LL long long const int MAXN = 1e7 + 10; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; int n,m,k,a[MAXN]; typedef pair<int,int> P; P b[MAXN]; vector<int>ans; int main() { cin >> n >> m >> k; ans.clear(); memset(a,0,sizeof a); memset(b,0,sizeof b); int tmp; for(int i = 0; i < n; i++) { scanf("%d",&tmp); a[tmp]++; } for(int i = 1; i <= m; i++) { scanf("%d",&b[i].first); b[i].second = i; } sort(b + 1,b + m + 1); int j = m; for(int i = 1e7; i >= 1; i--) { if(a[i] >= k) //这一天喝的牛奶和不玩的话,只能前面的一天多喝一点了 { a[i - 1] += (a[i] - k); continue; } while(j && b[j].first >= i && a[i] < k) //如果这一天还可以和的话就去商店看能不能再多买几瓶 { ans.push_back(b[j].second); a[i]++; j--; } } if(a[0] > k)//说明喝不完 puts("-1"); else { while(j && a[0] < k)//第一天喝的完的话看看可不可以再去买几瓶 { ans.push_back(b[j].second); a[0] ++; j--; } printf("%d ",ans.size()); sort(ans.begin(),ans.end()); for(int i = 0; i < ans.size(); i++) printf("%d%c",ans[i],i == ans.size() - 1 ? ' ' : ' '); } }
E - Change-free
CodeForces - 767E
题意:有100元的纸币和1元的硬币,某同学有无限多的纸币和 m 个硬币,并决定接下来的 n 天去食堂每天花费 c[i] 元。已知食堂大叔在第 i 天找零 x 元的话,不满意度会增加 w[i],问最小不满意度
题解:按顺序先直接使用手上有的硬币,当手上硬币剩余为负数的时候,说明前面一定会出现有一天需要多使用一张纸币,取的策略就是取前面的代价 w[i]*(100-a[i]%100) 最少的一次,然后手里剩余硬币 +100。用优先队列维护即可。
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<vector> #include<queue> #include<string.h> using namespace std; #define LL long long const int MAXN = 1e5 + 10; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; LL n,m,c[MAXN],w[MAXN]; bool vis[MAXN]; LL ans = 0; struct node { LL id,val; bool operator < (const node &a) const { return val > a.val; } }; priority_queue<node>que; int main() { memset(vis,false,sizeof vis); scanf("%lld %lld",&n,&m); for(int i = 1; i <= n; i++) scanf("%lld",&c[i]); for(int i = 1; i <= n; i++) scanf("%lld",&w[i]); for(int i = 1; i <= n; i++) { if(c[i] % 100 != 0) { que.push({i, w[i] * (100 - c[i] % 100)}); m -= c[i] % 100; if(m < 0) { node tmp = que.top(); que.pop(); vis[tmp.id] = true; ans += tmp.val; m += 100; } } } printf("%lld ",ans); for(int i = 1; i <= n; i++) { if(vis[i]) printf("%lld %lld ",c[i] / 100 + 1,0); else printf("%lld %lld ",c[i] / 100,c[i] % 100); } }