ZOJ Monthly, January 2019

Posted dup4

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ZOJ Monthly, January 2019相关的知识,希望对你有一定的参考价值。

 

A: Little Sub and Pascal‘s Triangle

Solved.

题意:求杨辉三角第n行奇数个数

思路:薛聚聚说找规律,16说Lucas

技术分享图片
 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 
 7 ll n;
 8 
 9 int main()
10 {
11     int t;
12     scanf("%d", &t);
13     while(t--)
14     {
15         scanf("%lld", &n);
16         n--;
17         ll tmp = 0;
18         while(n)
19         {
20             if(n & 1) tmp++;
21             n >>= 1;
22         }
23         ll ans = 1ll << tmp;
24         printf("%lld
", ans);
25     }
26     return 0;
27 }
View Code

 

 

B:Little Sub and his Geometry Problem

Solved.

题意:

一个点的权值定义为它到左下角所有点的曼哈顿距离

q次查询, 每次查询权值为c的点的个数

思路:

$给出的点沿着x轴正方向, y轴正方向都是严格单调递增的。$

$因此可以枚举x轴, 动态维护左下角点个数以及权值, 向右走的同时$

$将横坐标相同, 纵坐标<=当前位置的点假如, 向下走的时候将纵坐标相同给的点移除$

$当前权值为c时 ans++$

(薛聚聚:不会写题解啊)

技术分享图片
 1 #include<bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 typedef long long ll;
 6 typedef unsigned long long ull;
 7 
 8 const double eps = 1e-8;
 9 const ll MOD = 1e9 + 7;
10 const ll INFLL = 0x3f3f3f3f3f3f3f3f;
11 const int INF = 0x3f3f3f3f;
12 const int maxn = 1e5 + 10;
13 
14 int n, k;
15 ll sum, cnt;
16 ll sum_arr[maxn], cnt_arr[maxn];
17 ll ans[20];
18 
19 struct node {
20     int x, y;
21     node() {}
22     node(int x, int y) :x(x), y(y) {}
23     bool operator < (const node &other) const
24     {
25         return x == other.x ? y < other.y : x < other.x;
26     }
27 }P[maxn];
28 
29 ll solve(ll c)
30 {
31     cnt = sum = 0;
32     memset(sum_arr, 0, sizeof sum_arr);
33     memset(cnt_arr, 0, sizeof cnt_arr);
34     int index = 1;
35     int ans = 0;
36     int y = n;
37     for (int x = 1; x <= n; ++x)
38     {
39         while (index <= k && P[index].x <= x)
40         {
41             if (P[index].y <= y)
42             {
43                 cnt++;
44                 sum += P[index].x + P[index].y;
45                 sum_arr[P[index].y] += P[index].x + P[index].y;
46                 cnt_arr[P[index].y]++;
47             }
48             ++index;
49         }
50         while ((x + y) * cnt - sum > c)
51         {
52             sum -= sum_arr[y];
53             cnt -= cnt_arr[y];
54             --y;
55         }
56         if ((x + y) * cnt - sum == c) ++ans;
57     }
58     return ans;
59 }
60 
61 void RUN()
62 {
63     int t;
64     scanf("%d", &t);
65     while (t--)
66     {
67         scanf("%d %d", &n, &k);
68         for (int i = 1; i <= k; ++i) scanf("%d %d", &P[i].x, &P[i].y);
69         sort(P + 1, P + 1 + k);
70         int q;
71         scanf("%d", &q);
72         for (int i = 1; i <= q; ++i)
73         {
74             ll c;
75             scanf("%lld
", &c);
76             ans[i] = solve(c);
77         }
78         for (int i = 1; i <= q; ++i) printf("%lld%c", ans[i], " 
"[i == q]);
79     }
80 }
81 
82 int main()
83 {
84 #ifdef LOCAL_JUDGE
85     freopen("Text.txt", "r", stdin);
86 #endif // LOCAL_JUDGE
87 
88     RUN();
89 
90 #ifdef LOCAL_JUDGE
91     fclose(stdin);
92 #endif // LOCAL_JUDGE
93     return 0;
94 }
View Code

 

 

E:Little Sub and Mr.Potato‘s Math Problem

Solved.

题意:

给出n, k

将n个数按照字典序排序, k所在的位置为m

现在给出k, m  求最小的n

思路:

当k为10的整数倍, 那么它一定在第$log_{10^k}$

$随后统计当n=k的时候, 排在k前面的个数,和m比较, 判断是否合法$

$接着不断增加n, 统计每次增长排在k前面的个数, 随后输出n$

(薛聚聚:不会写题解啊)

技术分享图片
  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 typedef long long ll;
  6 typedef unsigned long long ull;
  7 
  8 const double eps = 1e-8;
  9 const ll MOD = 1e9 + 7;
 10 const ll INFLL = 0x3f3f3f3f3f3f3f3f;
 11 const int INF = 0x3f3f3f3f;
 12 const int maxn = 1e5 + 10;
 13 
 14 ll k, m;
 15 int arr[maxn];
 16 ll pow_10[10];
 17 
 18 void Init()
 19 {
 20     pow_10[0] = 1;
 21     for (int i = 1; i <= 18; ++i)
 22     {
 23         pow_10[i] = pow_10[i - 1] * 10;
 24     }
 25 }
 26 
 27 void solve()
 28 {
 29     ll num = 1;
 30     for (int i = 1;; ++i)
 31     {
 32         if (num > k) break;
 33         else if (num == k)
 34         {
 35             if (i == m)
 36             {
 37                 printf("%lld
", k);
 38                 return;
 39             }
 40             else
 41             {
 42                 puts("0");
 43                 return;
 44             }
 45         }
 46         num *= 10;
 47     }
 48     int len = 0;
 49     num = k;
 50     while (num)
 51     {
 52         arr[++len] = num % 10;
 53         num /= 10;
 54     }
 55     reverse(arr + 1, arr + 1 + len);
 56     ll ans = 0;
 57     num = 0;
 58     for (int i = 1; i <= len; ++i)
 59     {
 60         num = num * 10 + arr[i];
 61         ans += num - pow_10[i - 1];
 62         if (i != len) ++ans;
 63     }
 64     if (ans >= m)
 65     {
 66         puts("0");
 67         return;
 68     }
 69     else if (ans == m - 1)
 70     {
 71         printf("%lld
", k);
 72         return;
 73     }
 74     while (1)
 75     {
 76         len++;
 77         num *= 10;
 78         if (ans + num - pow_10[len - 1] >= m - 1)
 79         {
 80             ans = pow_10[len - 1] + m - ans - 2;
 81             printf("%lld
", ans);
 82             return;
 83         }
 84         ans += num - pow_10[len - 1];
 85     }
 86 }
 87 
 88 void RUN()
 89 {
 90     Init();
 91     int t;
 92     scanf("%d", &t);
 93     while (t--)
 94     {
 95         scanf("%lld %lld", &k, &m);
 96         solve();
 97     }
 98 }
 99 
100 int main()
101 {
102 #ifdef LOCAL_JUDGE
103     freopen("Text.txt", "r", stdin);
104 #endif // LOCAL_JUDGE
105 
106     RUN();
107 
108 #ifdef LOCAL_JUDGE
109     fclose(stdin);
110 #endif // LOCAL_JUDGE
111     return 0;
112 }
View Code

 

F:Little Sub and a Game

Unsolved.

题意:

有两个玩家$A, B 刚开始有一个变量v = 0$

$A玩家有N个pair, B玩家有M个pair ;; pair 为(x, y) A玩家N次操作,每次选择x_i 或者 y_i 来异或v B玩家有M次操作$

$A玩家先进行N次操作, B玩家再进行M次操作$

A玩家想让$v尽量大,B玩家想让v尽量小$

两个玩家都采用最优策略,求最后$v$的值

 

G:Little Sub and Tree

Solved.

题意:

给出一个无根树,选取$k个点对所有点进行编码$

按如下方式进行编码

$令选取的k个点为 s_1, s_2 cdots s_k$

编出的码有$k位$

$对于u来说,第i位的编码为 s_i -> u的简单路径上的点的总数$

思路:

如果是一条链的话  那么取两端的一个就可以了

那么我们考虑一棵树中,如果某个节点的儿子对应的子树是一条链

那么这条链是可以被缩点成一个叶节点 而对答案没有影响

那么现在树就被我们简化成了 只有叶节点的子树

首先注意到,一棵子树内节点的区分和这棵子树外的点的选取是没有关系的

那么我们考虑 一个点对应的儿子当中,如果有$x个叶节点$

那么这x个节点要想被区分,就需要取$x - 1$ 个

再考虑一个点的儿子对应的子树,如果子树内都被区分了,那么合并起来也是被区分的

那么考虑选谁作为根

只要根不在链上就可以了,因为如果在链上会对缩点产生影响

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

 

I:Little Sub and Isomorphism Sequences

Solved.

题意:

有一个$A[], 两种操作$

  • $A_x -> y$
  • 查询最长同构子串

思路:

考虑最长同构子串肯定会有重叠部分,那么两端出去的部分就是不同的部分

那么这个不同的部分让它长度为1即可,因为多余的长度是没有用的

那么题意就可以转化为 找一个最长的子串,使得两端相同即可

将数据离散化 开2e5个set维护每个数的位置

然后用数据结构 维护答案的最大值 即可

技术分享图片
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define N 200010
 5 int t, n, m, a[N], b[N];
 6 struct qnode
 7 {
 8     int op, x, y;
 9     void scan()
10     {
11         scanf("%d", &op);
12         if (op == 1) 
13         {
14             scanf("%d%d", &x, &y);
15             b[++b[0]] = y;
16         }
17     }
18 }q[N];
19 set <int> s[N];
20 namespace SEG
21 {
22     int a[N << 2];
23     void build(int id, int l, int r)
24     {
25         a[id] = -1;
26         if (l == r) return;
27         int mid = (l + r) >> 1;
28         build(id << 1, l, mid);
29         build(id << 1 | 1, mid + 1, r);
30     }
31     void update(int id, int l, int r, int pos, int v)
32     {
33         if (l == r)
34         {
35             a[id] = v;
36             return;
37         }
38         int mid = (l + r) >> 1;
39         if (pos <= mid) update(id << 1, l, mid, pos, v);
40         else update(id << 1 | 1, mid + 1, r, pos, v);
41         a[id] = max(a[id << 1], a[id << 1 | 1]);
42     }
43 }
44 void Hash()
45 {
46     sort(b + 1, b + 1 + b[0]);
47     b[0] = unique(b + 1, b + 1 + b[0]) - b - 1;
48     for (int i = 1; i <= n; ++i) a[i] = lower_bound(b + 1, b + 1 + b[0], a[i]) - b;
49     for (int i = 1; i <= m; ++i) if (q[i].op == 1) q[i].y = lower_bound(b + 1, b + 1 + b[0], q[i].y) - b;
50 }
51 
52 int main()
53 {
54     scanf("%d", &t);
55     while (t--)
56     {
57         scanf("%d%d", &n, &m);
58         SEG::build(1, 1, n + m);
59         for (int i = 1; i <= n + m; ++i) s[i].clear(); b[0] = 0;
60         for (int i = 1; i <= n; ++i) scanf("%d", a + i), b[++b[0]] = a[i];
61         for (int i = 1; i <= m; ++i) q[i].scan(); Hash();
62         for (int i = 1; i <= n; ++i) s[a[i]].insert(i);
63         for (int i = 1; i <= n + m; ++i) if (s[i].size() >= 2)
64             SEG::update(1, 1, n + m, i, *s[i].rbegin() - *s[i].begin());
65         for (int i = 1; i <= m; ++i)
66         {
67             if (q[i].op == 1)
68             {
69                 int v = a[q[i].x], x = q[i].x, y = q[i].y; 
70                 s[v].erase(x);
71                 SEG::update(1, 1, n + m, v, s[v].size() >= 2 ? *s[v].rbegin() - *s[v].begin() : -1);
72                 a[q[i].x] = y;
73                 v = y;
74                 s[v].insert(x);
75                 SEG::update(1, 1, n + m, v, s[v].size() >= 2 ? *s[v].rbegin() - *s[v].begin() : -1);
76             }
77             else printf("%d
", SEG::a[1]);
78         }
79     }
80     return 0;
81 }
View Code

 

以上是关于ZOJ Monthly, January 2019的主要内容,如果未能解决你的问题,请参考以下文章

ZOJ Monthly, January 2019 Little Sub and Isomorphism Sequences 离线离散化 + set + multiset

[ZOJ]ZOJ Monthly, January 2018

ZOJ Monthly, January 2018 Solution

ZOJ Monthly, March 2018

ZOJ Monthly, November 2012

ZOJ Monthly, June 2018 - I District Division