Codeforces Round #398 (Div. 2) BCD
B:The Queue
题目大意:你要去办签证,那里上班时间是[s,t), 你知道那一天有n个人会来办签证,他们分别是在时间点ai来的。每个人办业务要花相同的时间x,问你什么时候来 排队等待的时间最少。 (如果你和某个人同时来排队,你会排在他后面) 所有时间为正整数。
题解:
首先可以模拟出 每个人的业务什么时候会办好,那么最优解要么是在第一个人来之前的一分钟来,即a1-1,要么是在某个人的业务刚办好的时候来。 分别求出要等待的时间即可。
注意如果有多个人同时来,那么只能在这些人里的最后的业务办好之后来。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream>
2 #include <cstdio>
3 #include <cmath>
4 #include <cstring>
5 #include <algorithm>
6 #include <vector>
7 #include <map>
8 #include <cstdlib>
9 #include <set>
10 #include <queue>
11 using namespace std;
12
13 #define X first
14 #define Y second
15 #define Mod 1000000007
16 #define N 1000010
17 #define M 101
18
19 typedef long long ll;
20 typedef pair<int,int> pii;
21
22 int n;
23 ll s,t,x,ans1,ans2;
24 ll v[N];
25
26 int main()
27 {
28 //freopen("in.in","r",stdin);
29 //freopen("out.out","w",stdout);
30
31 scanf("%I64d%I64d%I64d",&s,&t,&x);
32 scanf("%d",&n);
33
34 for (int i=1;i<=n;i++) scanf("%I64d",&v[i]);
35 while (n && v[n]+x>t) n--;
36 if (n==0)
37 {
38 printf("%I64d\n",s);
39 return 0;
40 }
41
42 ans1=v[1]-1; ans2=s-ans1;
43
44 ll cur=s;
45 for (int i=1;i<=n;i++)
46 {
47 if (v[i]<=cur) cur+=x;
48 else cur=v[i]+x;
49 if (i<n && v[i]==v[i+1]) continue;
50 if (i<n)
51 {
52 ll tmp=v[i+1]-1,tt=max(0ll,cur-tmp);
53 if (tt<ans2) ans1=tmp,ans2=tt;
54 }
55 //cout<<i<<' '<<cur<<endl;
56 }
57 if (cur+x<=t)
58 {
59 ans1=cur,ans2=0;
60 }
61 printf("%I64d\n",ans1);
62 return 0;
63 }
C:Garland
题目大意:
给出一棵树,要求分成3部分,每个部分的点权和相同。
题解:
首先所有点的点权之和必须是3的倍数,否则无解。记s[x]为以x为根的子树点权和,tmp=所有点权和/3。假设我们选了u,v这两个点,并且切掉了它们到它们的父节点的边。那么符合要求的只有2种情况:
1. s[u]=s[v]=tmp. lca(u,v)!=u && lca(u,v)!=v.
2. s[u]=tmp*2,s[v]=tmp, lca(u,v)=u.
首先做一次dfs求出所有s[x]。
然后做第二次dfs:对于第2种情况,只要记录从根到当前节点是否存在s[u]=tmp*2的点, 如果存在,且当前节点s[v]=tmp,那么就找到了一种分割方案。
对于第1种情况, 对于当前节点v, 且s[v]=tmp, 我们需要知道是否存在一个点u,满足s[u]=tmp*2,且u不在 根到v的路径中。 这里用点小技巧, 假设dfs到了v,那么根到v的路径中的点都还在栈里, 所以只要考虑已经不在栈里的点u。 具体实现看代码。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream>
2 #include <cstdio>
3 #include <cmath>
4 #include <cstring>
5 #include <algorithm>
6 #include <vector>
7 #include <map>
8 #include <cstdlib>
9 #include <set>
10 #include <queue>
11 using namespace std;
12
13 #define X first
14 #define Y second
15 #define Mod 1000000007
16 #define N 1000010
17 #define M 101
18
19 typedef long long ll;
20 typedef pair<int,int> pii;
21
22 int n,t1,t2,rt,tmp,tt;
23 int father[N],v[N],s[N];
24 vector<int> g[N];
25
26 void Dfs(int x)
27 {
28 s[x]=v[x];
29 for (int i=0;i<g[x].size();i++)
30 {
31 int y=g[x][i]; if (y==father[x]) continue;
32 Dfs(y); s[x]+=s[y];
33 }
34 }
35
36 void Dfs2(int x,int pre)
37 {
38 if (pre && s[x]==tmp) t1=pre,t2=x;
39 if (tt && s[x]==tmp) t1=tt,t2=x;
40 for (int i=0;i<g[x].size();i++)
41 {
42 int y=g[x][i]; if (y==father[x]) continue;
43 if (x!=rt && s[x]==tmp*2) Dfs2(y,x);
44 else Dfs2(y,pre);
45 }
46 if (s[x]==tmp) tt=x;
47 }
48
49 int main()
50 {
51 //freopen("in.in","r",stdin);
52 //freopen("out.out","w",stdout);
53
54 scanf("%d",&n); int sum=0;
55 for (int i=1;i<=n;i++)
56 {
57 scanf("%d%d",&father[i],&v[i]);
58 if (father[i]) g[father[i]].push_back(i);
59 else rt=i;
60 sum+=v[i];
61 }
62 if (sum%3){printf("-1\n"); return 0;}
63 tmp=sum/3;
64
65 Dfs(rt);
66 Dfs2(rt,0);
67 if (t1 && t2) printf("%d %d\n",t1,t2);
68 else printf("-1\n");
69 return 0;
70 }
D:
有n瓶牛奶,分别还有ai天过期,每天最多喝k瓶。 超市里有m瓶牛奶,分别还有bi天过期, 问最多能从超市里买多少瓶牛奶,使得买来的牛奶加上本来已有的,都可以在过期之前喝完。
n<=100w.
题解:
显然要先买保质期长的牛奶,所以可以考虑二分答案。 如何判断可行性呢? 根据贪心策略,显然要先喝保质期短的牛奶。所以只要把牛奶按保质期排序就好。这里就涉及到将两个单调的序列合并成一个单调序列的问题。 数据范围100w应该是为了卡掉暴力sort合并的O(nlognlogn)解法.
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream>
2 #include <cstdio>
3 #include <cmath>
4 #include <cstring>
5 #include <algorithm>
6 #include <vector>
7 #include <map>
8 #include <cstdlib>
9 #include <set>
10 #include <queue>
11 using namespace std;
12
13 #define X first
14 #define Y second
15 #define Mod 1000000007
16 #define N 1000010
17 #define M 101
18
19 typedef long long ll;
20 typedef pair<int,int> pii;
21
22 int n,m,k;
23 int a[N],q[N<<1];
24
25 struct node
26 {
27 int v,id;
28 bool operator < (const node &t)const
29 {
30 return v<t.v;
31 }
32 }b[N];
33
34 bool check(int mid)
35 {
36 int i=0,j=mid,cnt=0;
37 while (i<n || j<m)
38 {
39 if (i>=n) q[cnt]=b[j].v,j++;
40 else if (j>=m) q[cnt]=a[i],i++;
41 else
42 {
43 if (a[i]<b[j].v) q[cnt]=a[i],i++;
44 else q[cnt]=b[j].v,j++;
45 }
46 if (cnt/k>q[cnt]) return false;
47 cnt++;
48 }
49 return true;
50 }
51
52 int main()
53 {
54 //freopen("in.in","r",stdin);
55 //freopen("out.out","w",stdout);
56
57 scanf("%d%d%d",&n,&m,&k);
58 for (int i=0;i<n;i++) scanf("%d",&a[i]);
59 for (int i=0;i<m;i++) scanf("%d",&b[i].v),b[i].id=i+1;
60 sort(a,a+n);sort(b,b+m);
61 bool flag=true;
62 for (int i=0;i<n;i++) if (a[i]<i/k) flag=false;
63 if (!flag){printf("-1\n"); return 0;}
64
65 int l=0,r=m,mid,ans;
66 while (l<r)
67 {
68 mid=(l+r)>>1;
69 if (check(mid)) r=mid;
70 else l=mid+1;
71 }
72
73 ans=m-l;
74 printf("%d\n",ans);
75 for (int i=m-ans;i<m;i++) printf("%d ",b[i].id);
76 printf("\n");
77 return 0;
78 }