ZOJ Monthly, June 2018 Solution

A - Peer Review

Water.

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int t, n;
 5 
 6 int main()
 7 {
 8     scanf("%d", &t);
 9     while (t--)
10     {
11         scanf("%d", &n);
12         for (int i = 1; i <= n; ++i) printf("0%c", " \n"[i == n]);
13     }
14     return 0;
15 }
View Code

 

 

B - Boring Game

Unsolved. 

C - Enigma Machine

Unsolved.

 

D - Number Theory

Unsolved.

 

E - Chasing

Solved.

题意:两个人在一个二维平面上,刚开始两个人在第二象限或者第三象限,A跑到Y轴B就不能追了,B的速度是A的K倍,求B能否追到B

思路:k < 0 那么必然不行

k == 0 判断是不是在同一高度,如果是判断起始位置

k > 0  假设y轴上存在某个点 使得A B 能够在该点相遇,列方程求解

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 double xa, xb, ya, yb, k;
 6 
 7 int main()
 8 {
 9     int t;
10     scanf("%d", &t);
11     while(t--)
12     {
13         scanf("%lf %lf %lf %lf %lf", &xa, &ya, &xb, &yb, &k);
14         if(k < 1.0)
15         {
16             puts("N");
17         }
18         else if(k == 1.0)
19         {
20             if(ya != yb) puts("N");
21             else if(xb < xa) puts("N");
22             else puts("Y");
23         }
24         else
25         {
26             double a = k * k - 1.0;
27             double b = -2.0 * k * k * ya + 2.0 * yb;
28             double c = k * k * xa * xa - xb * xb + k * k * ya * ya - yb * yb;
29             double d = b * b - 4.0 * a * c;
30             if(d >= 0) puts("N");
31             else puts("Y");
32         }
33     }    
34     return 0;
35 }
View Code

 

F - Carrot Gathering

Unsolved.

 

G - Virtual Singers

Upsolved.

题意:

 

H - How Many Palindromes

Unsolved.

 题意:

有$n个A数和m个B数 m <= n,对每个B数都匹配一个A数,使得\sum_{i = 1}^{i = m} |B[i] - A[i]| 最小$

思路:

考虑费用流的思想,维护三个堆

将$A、B 数放在一起排序,然后从左往右枚举$

$如果当前数是A$

  如果左边有未匹配的$B_1数,那么与之匹配即可,此操作不用考虑反悔操作$

  $因为假如有另一个B_2,使得B_2 与 这个A匹配更优$

  那么后面必然要有另一个$A_2 来匹配这个B_1 $

  $贡献是 A_2 - B_1 + B_2 - A_1 这个式子显然小于 A_2 - B_2 + A_1 - B_1$

  因为这四个数字存在大小关系

  $A_2 - B_1 大于 A_2 - B_2 + A_1 - B_1$

  如果左边没有未匹配的$B_1数,那么考虑B的反悔操作是否更优$

  $更优的话就反悔并且将代价取反并算上A往右匹配的贡献放入堆Q_A中, 相当于反悔操作$

$如果当前数是B$

  $如果左边有未匹配的A数,那么与之匹配,并且将代价取反并且算上B往右匹配的贡献放入堆Q_C中$

  否则放入堆$Q_B$中表示还未匹配

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define ll long long
 5 #define N 100010
 6 int t, n, m; ll x;
 7 struct node 
 8 {
 9     ll v; int Type;
10     node () {}
11     node (ll v, int Type) : v(v), Type(Type) {}
12     bool operator < (const node &r) const { return v < r.v; }   
13 }arr[N << 1];
14 priority_queue <ll, vector <ll> , greater <ll> > A, B, C;  
15 
16 int main()
17 {
18     scanf("%d", &t);
19     while (t--)
20     {
21         while (!A.empty()) A.pop();
22         while (!B.empty()) B.pop();
23         while (!C.empty()) C.pop();
24         scanf("%d%d", &n, &m);
25         for (int i = 1; i <= n; ++i) 
26         {
27             scanf("%lld", &x);
28             arr[i] = node(x, 0);
29         }
30         for (int i = 1; i <= m; ++i)
31         {
32             scanf("%lld", &x);
33             arr[n + i] = node(x, 1);
34         }
35         sort(arr + 1, arr + 1 + n + m);
36         ll res = 0;
37         for (int i = 1; i <= n + m; ++i)
38         {
39             if (arr[i].Type == 1)
40             {
41                 if (!A.empty())
42                 {
43                     x = A.top(); A.pop();
44                     res += arr[i].v + x;
45                     C.push(-x - 2 * arr[i].v);
46                 }
47                 else 
48                     B.push(-arr[i].v); 
49             }
50             else
51             {
52                 if (!B.empty())
53                 {
54                     x = B.top(); B.pop();
55                     res += arr[i].v + x;
56                 }
57                 else if (!C.empty()) 
58                 {
59                     x = C.top(); 
60                     if (arr[i].v + x < 0)
61                     {
62                         C.pop();
63                         res += arr[i].v + x;
64                         A.push(-x - 2 * arr[i].v);
65                     }
66                     else 
67                         A.push(-arr[i].v);
68                 }
69                 else
70                     A.push(-arr[i].v); 
71             }
72         }
73         printf("%lld\n", res);
74     }
75     return 0;
76 }
View Code

 

 

I - District Division

Solved.

题意:给出一棵树,求能不能分成$\frac{n}{k}$ 个连通块,使得每块个数为k

思路:如果存在合法分法,那么必然存在某个子树大小为k,DFS下去,再回溯上来判断即可,遇到大小为k的子树就分块

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int maxn = 1e5 + 10;
 6 
 7 int n, k;
 8 
 9 int val[maxn];
10 int fa[maxn];
11 int vis[maxn];
12 int cnt;
13 vector<int>root;
14 vector<int>G[maxn];
15 
16 void Init()
17 {
18     cnt = 0;
19     root.clear();
20     for(int i = 1; i <= n; ++i)
21     {
22         val[i] = vis[i] = 0;
23         fa[i] = i;
24         G[i].clear();
25     }    
26 }
27 
28 void DFS(int u, int pre)
29 {
30     val[u] = 1;
31     fa[u] = pre;
32     for(int i = 0, len = G[u].size(); i < len; ++i)
33     {
34         int v = G[u][i];
35         if(v == pre) continue;
36         DFS(v, u);
37         val[u] += val[v];
38     }
39     if(val[u] == k)
40     {
41         cnt++;
42         val[u] = 0;
43         root.push_back(u);
44     }
45 }
46 
47 void DFS2(int u, int pre)
48 {
49     if(vis[u]) return ;
50     vis[u] = 1;
51     printf("%d%c", u, " \n"[cnt == k]);
52     cnt++;
53     for(int i = 0, len = G[u].size(); i < len; ++i)
54     {
55         int v = G[u][i];
56         if(v == pre) continue;
57         DFS2(v, u);
58     }
59 }
60 
61 int main()
62 {
63     int t;
64     scanf("%d", &t);
65     while(t--)
66     {
67         scanf("%d %d", &n, &k);
68         Init();
69         for(int i = 1; i < n; ++i)
70         {
71             int u, v;
72             scanf("%d %d", &u, &v);
73             G[u].push_back(v);
74             G[v].push_back(u);
75         }
76         DFS(1, -1);
77         if(cnt != n / k)
78         {
79             puts("NO");
80             continue;
81         }
82         puts("YES");
83         for(int i = 0, len = root.size(); i < len; ++i)
84         {
85             cnt = 1;
86             DFS2(root[i], fa[root[i]]);
87         }
88     }    
89     return 0;
90 }
View Code

 

J - Good Permutation

Solved.

题意:每次能够交换相邻两个数,求最少交换次数使得满足题目给出的序列条件

思路:通过枚举每次在第一位的数,从而递推下一种状态,比如12345推出51234即加上5移到第一位的步数再减去5带来的贡献

 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 
 7 const int maxn = 1e5 + 10;
 8 
 9 int n;
10 int arr[maxn];
11 int pos[maxn];
12 int a[maxn];
13 
14 int lowbit(int p)
15 {
16     return p & (-p);
17 }
18 
19 void update(int p)
20 {
21     while(p <= n)
22     {
23         a[p]++;
24         p += lowbit(p);
25     }
26 }
27 
28 int query(int p)
29 {
30     int res = 0;
31     while(p)
32     {
33         res += a[p];
34         p -= lowbit(p);
35     }
36     return res;
37 }
38 
39 int main()
40 {
41     int t;
42     scanf("%d", &t);
43     while(t--)
44     {
45         scanf("%d", &n);
46         ll ans = 0;
47         for(int i = 1; i <= n; ++i) a[i] = 0;
48         for(int i = 1; i <= n; ++i)
49         {
50             scanf("%d", arr + i);
51             pos[arr[i]] = i;
52         }
53         for(int i = n; i >= 1; --i)
54         {
55             ans += query(arr[i] - 1);
56             update(arr[i]);
57         }
58         ll tmp = ans;
59         for(int i = 1; i <= n; ++i)
60         {
61             tmp = tmp + n - pos[i] - (pos[i] - 1);
62             ans = min(ans, tmp);
63         }
64         printf("%lld\n", ans);
65     }
66     return 0;
67 }
View Code
posted @ 2018-10-31 16:47  Dup4  阅读(305)  评论(0编辑  收藏  举报