2017-2018 ACM-ICPC, Asia Tsukuba Regional Contest

Problem A Secret of Chocolate Poles

Solved.

题意:有两种物品长度为1以及k, 求在长度为l 的箱子里放置物品的方案数, 每两个物品间有一个长度为1的空白

思路:$dp[i][0/1]$ $i$表示当前高度, $0/1$表示放不放

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 
 7 const int maxn = 1e3 + 10;
 8 
 9 int l, k;
10 ll dp[maxn][2];
11 
12 int main()
13 {
14     while(~scanf("%d %d", &l, &k))
15     {
16         memset(dp, 0, sizeof dp);
17         dp[1][1] = 1;
18         dp[k][1] = 1;
19         for(int i = 1; i <= l; ++i)
20         {
21             dp[i + 1][0] += dp[i][1];
22             dp[i + 1][1] += dp[i][0];
23             dp[i + k][1] += dp[i][0];
24         }
25         ll ans = 0;
26         for(int i = 1; i <= l; ++i) ans += dp[i][1];
27         printf("%lld\n", ans);
28     }
29     return 0;
30 }
View Code

Problem B Parallel Lines

Solved.

题意:有n个点, 将这些点两两匹配, 求最后平行条数

思路:DFS搜索, 复杂度为$O(15 \cdot 13 \cdot 11 \cdot 9 \cdot 7 \cdot 5 \cdot 3)$

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int maxn = 4e3 + 10;
 6 
 7 int gcd(int a,int b)
 8 {
 9     return b == 0 ? a : gcd(b, a % b);
10 }
11 
12 struct node{
13     int x, y;
14     node(){}
15     node(int x, int y):x(x), y(y){}
16 }arr[maxn];
17 
18 int n;
19 int ans;
20 int vis[maxn];
21 int G[maxn][maxn];
22 int X[maxn][maxn], Y[maxn][maxn];
23 
24 void DFS(int cnt, int res)
25 {
26     if(cnt + 2 > n) 
27     {
28         ans = max(ans, res);
29         return ;
30     }
31     int pos1 = -1;
32     for(int i = 1; i <= n; ++i) if(!vis[i])
33     {
34         pos1 = i;
35         vis[i] = 1;
36         break;
37     }
38     for(int i = 1; i <= n; ++i) if(!vis[i])
39     {
40         int pos2 = i;
41         vis[i] = 1;
42         int tmp = res;
43         int dx = X[pos1][pos2];
44         int dy = Y[pos1][pos2];
45         tmp += G[dx][dy];
46         G[dx][dy]++;
47         DFS(cnt + 2, tmp);
48         G[dx][dy]--;
49         vis[pos2] = 0;
50     }
51     vis[pos1] = 0;
52 }
53 
54 
55 int main()
56 {
57     while(~scanf("%d", &n))
58     {
59         memset(vis, 0, sizeof vis);
60         for(int i = 1; i <= n; ++i) scanf("%d %d", &arr[i].x, &arr[i].y);
61         for(int i = 1; i <= n; ++i) 
62         {
63             for(int j = i + 1; j <= n; ++j)
64             {
65                 int dx = arr[j].x - arr[i].x;
66                 int dy = arr[j].y - arr[i].y;
67                 int GCD = gcd(dx, dy);
68                 dx /= GCD;
69                 dy /= GCD;
70                 dx += 2000;
71                 dy += 2000;
72                 X[i][j] = dx;
73                 Y[i][j] = dy;
74             }
75         }
76         ans = 0;
77         DFS(0, 0);
78         printf("%d\n", ans);
79     }
80     return 0;
81 }
View Code

Problem C Medical Checkup

扫描二维码关注公众号,回复: 5522221 查看本文章

Solved.

题意:有$n$个人去做体检,体检项目无限个,每个人完成一个项目的时间为$h_i$,按顺序做,没轮到就排队 求时刻$t$的时候每个人完成了多少个项目或者正在完成或者正在排队的也要算上

思路:如果$h_i >= h_{i - 1}$ 那么这个人去做,不会有等待时间,否则第一个项目等完后,考虑第二个的时候,需要等待$h_{i - 1} - h_i$的时间,加上自己完成的时间 刚好是$h_{i - 1}$

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 100010
 6 int n, t, a[N];
 7 
 8 int main()
 9 {
10     while (scanf("%d%d", &n, &t) != EOF)
11     {
12         for (int i = 1; i <= n; ++i) scanf("%d", a + i);
13         ll res = 0;
14         ll tot = 0;
15         for (int i = 1; i <= n; ++i)
16         {
17             tot += a[i];
18             res = 1;
19             a[i] = max(a[i], a[i - 1]); 
20             if (tot <= t + 1)
21             {
22                 ll now = t - tot + 1;
23                 res += now / a[i] + (now % a[i] != 0);
24             }
25             printf("%lld\n", res);
26         }
27     }
28     return 0;
29 }
View Code

Problem E Black or White

Solved.

题意:有两个字符串$s$和$t$, 字符只由'B'和'W'组成,操作时选取一段长度不超过$k$的子段,将这一段全染成'B'或者'W',求s -> t 最少操作数

思路:考虑是否跟前面的一起做,转移方程就是$dp[i] = Min_{j + k >= i}(dp[j - 1] + f(j, i))$

$dp[i]$表示处理到第$i$位的最少操作

线段树优化即可。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 
  4 #define N 500010
  5 int n, k;
  6 char a[N], b[N];
  7 int f[N];
  8 
  9 namespace SEG
 10 {
 11     struct node
 12     {
 13         int Min[2], lazy[2];
 14         void init()
 15         {
 16             memset(Min, 0, sizeof Min);
 17             memset(lazy, 0, sizeof lazy);
 18         }
 19         void add(int x, int vis)
 20         {
 21             Min[vis] += x;
 22             lazy[vis] += x;
 23         }
 24         node operator + (const node &other) const
 25         {
 26             node res; res.init();
 27             for (int i = 0; i < 2; ++i)
 28                 res.Min[i] = min(Min[i], other.Min[i]);
 29             return res;
 30         }
 31     }a[N << 2], res;
 32     void init()
 33     {
 34         memset(a, 0, sizeof a);
 35     }
 36     void pushdown(int id)
 37     {
 38         for (int i = 0; i < 2; ++i)
 39             if (a[id].lazy[i])
 40             {
 41                 int &x = a[id].lazy[i];
 42                 a[id << 1].add(x, i);
 43                 a[id << 1 | 1].add(x, i);
 44                 x = 0;
 45             }
 46     }
 47     void update(int id, int l, int r, int ql, int qr, int v, int vis)
 48     {
 49         if (qr < ql) return;
 50         if (l >= ql && r <= qr)
 51         {
 52             a[id].add(v, vis);
 53             return;
 54         }
 55         int mid = (l + r) >> 1;
 56         pushdown(id);
 57         if (ql <= mid) update(id << 1, l, mid, ql, qr, v, vis);
 58         if (qr > mid) update(id << 1 | 1, mid + 1, r, ql, qr, v, vis);
 59         a[id] = a[id << 1] + a[id << 1 | 1];
 60     }
 61     void query(int id, int l, int r, int ql, int qr)
 62     {
 63         if (qr < ql) return; 
 64         if (l >= ql && r <= qr)
 65         {
 66             res = res + a[id];
 67             return;
 68         }
 69         int mid = (l + r) >> 1;
 70         pushdown(id);
 71         if (ql <= mid) query(id << 1, l, mid, ql, qr);
 72         if (qr > mid) query(id << 1 | 1, mid + 1, r, ql, qr);
 73     }
 74 }
 75 // 0 all turn B
 76 // 1 all turn W
 77 
 78 int main()
 79 {
 80     while (scanf("%d%d", &n, &k) != EOF)
 81     {
 82         scanf("%s", a + 1);
 83         scanf("%s", b + 1);
 84         SEG::init();
 85         f[1] = (a[1] != b[1]);
 86         if (b[1] == 'W')
 87             SEG::update(1, 1, n, 1, 1, 1, 0);
 88         else
 89             SEG::update(1, 1, n, 1, 1, 1, 1);
 90         for (int i = 2; i <= n; ++i)
 91         {
 92             f[i] = f[i - 1] + (a[i] != b[i]);
 93             for (int j = 0; j < 2; ++j)
 94                 SEG::update(1, 1, n, i, i, f[i - 1], j);
 95             int last = max(1, i - k + 1); 
 96 //            printf("%d%c", last, " \n"[i == n]);
 97             // 0
 98             if (b[i] == 'W')
 99             {
100                 SEG::update(1, 1, n, i, i, 1, 0);
101                 if (b[i - 1] != 'W')
102                     SEG::update(1, 1, n, last, i - 1, 1, 0);
103             }
104             // 1
105             if (b[i] == 'B')
106             {
107                 SEG::update(1, 1, n, i, i, 1, 1);
108                 if (b[i - 1] != 'B')
109                     SEG::update(1, 1, n, last, i - 1, 1, 1);
110             }
111             for (int j = 0; j < 2; ++j)
112                 SEG::res.Min[j] = (int)1e9;
113             SEG::query(1, 1, n, last, i);
114             for (int j = 0; j < 2; ++j)
115                 f[i] = min(f[i], SEG::res.Min[j] + 1);
116 //            printf("%d %d %d\n", SEG::res.Min[0], SEG::res.Min[1], f[i]);
117 //            for (int j = 0; j < 2; ++j)
118 //                SEG::res.Min[j] = (int)1e9;
119 //            SEG::query(1, 1, n, i, i);
120 //            printf("%d %d\n", SEG::res.Min[0], SEG::res.Min[1]);
121         }
122         printf("%d\n", f[n]);
123     }
124     return 0;
125 }
View Code

Problem H Homework

Solved.

题意:有两种作业, 第一种作业有$m$种, 第二种作业有$n-m$种,每个作业有自己的startTime以及endTime, 每天选择一个集合做作业, 求最后能完成的最大值和最小值。

思路:

最大值很显然可以用最大流。

对于最小值, 可以将A类作业和源点相连以及自身对应的时间起点相连, B类作业和汇点相连以及自身对应的时间的终点相连,跑最小割。

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 typedef long long ll;
  6 
  7 const int INF = 0x3f3f3f3f;
  8 const int maxn = 1e6 + 10;
  9 
 10 struct Edge{
 11     int to, flow, nxt;
 12     Edge(){}
 13     Edge(int to, int nxt, int flow):to(to), nxt(nxt), flow(flow){}
 14 }edge[maxn << 2];
 15 
 16 struct node{
 17     int si, ti;
 18     node(){}
 19     node(int si, int ti):si(si), ti(ti){}
 20 }arr[maxn];
 21 
 22 int head[maxn], dep[maxn];
 23 
 24 int S, T;
 25 int n, m, tot;
 26 
 27 void Init()
 28 {
 29     memset(head, -1, sizeof head);
 30     tot = 0;
 31 }
 32 
 33 void addedge(int u,int v, int w, int rw = 0)
 34 {
 35     edge[tot] = Edge(v, head[u], w); head[u] = tot++;
 36     edge[tot] = Edge(u, head[v], rw); head[v] = tot++;
 37 }
 38 
 39 bool BFS()
 40 {
 41     memset(dep, -1, sizeof dep);
 42     queue<int>q;
 43     q.push(S);
 44     dep[S] = 1;
 45     while(!q.empty())
 46     {
 47         int u = q.front();
 48         q.pop();
 49         for(int i = head[u]; ~i; i = edge[i].nxt)
 50         {
 51             if(edge[i].flow && dep[edge[i].to] == -1)
 52             {
 53                 dep[edge[i].to] = dep[u] + 1;
 54                 q.push(edge[i].to);
 55             }
 56         }
 57     }
 58     return dep[T] < 0 ? 0 : 1;
 59 }
 60 
 61 int DFS(int u,int f)
 62 {
 63     if(u == T || f == 0) return f;
 64     int w, used = 0;
 65     for(int i = head[u]; ~i; i = edge[i].nxt)
 66     {
 67         if(edge[i].flow && dep[edge[i].to] == dep[u] + 1)
 68         {
 69             w = DFS(edge[i].to, min(f - used, edge[i].flow));
 70             edge[i].flow -= w;
 71             edge[i ^ 1].flow += w;
 72             used += w;
 73             if(used == f) return f;    
 74         }
 75     }
 76     if(!used) dep[u] = -1;
 77     return used;
 78 }
 79 
 80 int Dicnic()
 81 {
 82     int ans = 0;
 83     while(BFS())
 84     {
 85         ans += DFS(S, INF);
 86     }
 87     return ans;
 88 }
 89 
 90 int in[maxn], out[maxn], homework[maxn];
 91 
 92 int main()
 93 {
 94     while(~scanf("%d %d", &n, &m))
 95     {
 96         Init();
 97         for(int i = 1; i <= n; ++i) scanf("%d %d", &arr[i].si, &arr[i].ti);
 98         int cnt = 0;
 99         S = cnt++;
100         for(int i = 1; i <= 400; ++i) in[i] = cnt++, out[i] = cnt++;
101         for(int i = 1; i <= n; ++i) homework[i] = cnt++;
102         T = cnt++;
103         for(int i = 1; i <= n; ++i) addedge(S, homework[i], 1);
104         for(int i = 1; i <= n; ++i) for(int j = arr[i].si; j <= arr[i].ti; ++j)
105         {
106             addedge(homework[i], in[j], 1);
107         }
108         for(int i = 1; i <= 400; ++i) addedge(in[i], out[i], 1);
109         for(int i = 1; i <= 400; ++i) addedge(out[i], T, 1);
110         int ans1 = Dicnic();
111         
112         Init();
113         for(int i = 1; i <= m; ++i)
114         {
115             addedge(S, homework[i], 1);
116             for(int j = arr[i].si; j <= arr[i].ti; ++j)
117             {
118                 addedge(homework[i], in[j], 1);
119             }
120         } 
121         for(int i = 1; i <= 400; ++i) addedge(in[i], out[i], 1);
122         for(int i = m + 1; i <= n; ++i)
123         {
124             addedge(homework[i], T, 1);
125             for(int j = arr[i].si; j <= arr[i].ti; ++j)
126             {
127                 addedge(out[j], homework[i], 1);
128             }
129         }
130         int ans2 = Dicnic();
131         printf("%d\n%d\n", ans1, ans2);
132     }
133     return 0;
134 }
View Code

Problem I Starting a Scenic Railroad Service

Solved.

题意:求两种卖票方案需要提供的座位数。

思路:

对于第二种答案, 很显然可以用差分,求最大值得到。

对于第一种答案, 枚举在每个人, 求每个人上车前已经下车以及下车前还没上车的人数, 剩余的人数就是保证这个人上车有座位的座位数, 扫一遍求最大值即可。

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int maxn = 2e5 + 10;
 6 
 7 struct node{
 8     int l, r;
 9     node(){}
10     node(int l,int r):l(l), r(r){}
11 }arr[maxn];
12 
13 int n;
14 int ans1, ans2;
15 int sum[maxn];
16 int brr[maxn], crr[maxn];
17 
18 int main()
19 {
20     while(~scanf("%d", &n))
21     {
22         memset(sum, 0, sizeof sum);
23         ans1 = ans2 = 0;
24         for(int i = 1; i <= n; ++i)
25         {
26             scanf("%d %d", &arr[i].l, &arr[i].r);
27             arr[i].r--;
28             brr[i] = arr[i].r;
29             crr[i] = arr[i].l;
30             sum[arr[i].l]++, sum[arr[i].r + 1]--;
31         }
32         for(int i = 1; i < maxn; ++i)
33         {
34             sum[i] += sum[i - 1];
35             ans1 = max(ans1, sum[i]);
36         }
37         sort(brr + 1, brr + 1 + n);
38         sort(crr + 1, crr + 1 + n);
39         for(int i = 1; i <= n; ++i)
40         {
41             int L = lower_bound(brr + 1, brr + 1 + n, arr[i].l) - brr;
42             int R = upper_bound(crr + 1, crr + 1 + n, arr[i].r) - crr;
43             R--;
44             int tmp = n - (L - 1) - (n - R);
45             ans2 = max(ans2, tmp);
46         }
47         printf("%d %d\n", ans2, ans1);
48     }
49     return 0;
50 }
View Code

猜你喜欢

转载自www.cnblogs.com/Dup4/p/10525587.html