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\n", ans);
25     }
26     return 0;
27 }

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\n", &c);
76             ans[i] = solve(c);
77         }
78         for (int i = 1; i <= q; ++i) printf("%lld%c", ans[i], " \n"[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 }

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\n", 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\n", 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\n", 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 }

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\n1");
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\n%d\n", ans);
79             continue;
80         }
81         pre(root);
82         DFS(root);
83         //puts("bug");
84         //for (int i = 1; i <= n; ++i) printf("%d %d\n", i, fa[i]);
85         //puts("bug");
86         int k = res.size();
87         printf("%d\n", k);
88         for (int i = 0; i < k; ++i) printf("%d%c", res[i], " \n"[i == k - 1]);
89     }
90     return 0;
91 }

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\n", SEG::a[1]);
78         }
79     }
80     return 0;
81 }

原文地址:https://www.cnblogs.com/Dup4/p/10292338.html

时间: 2024-10-11 04:26:20

ZOJ Monthly, January 2019的相关文章

matrix_2015_1 138 - ZOJ Monthly, January 2015

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3844 第一个,n个数,每次操作最大数和最小数都变成他们的差值,最后n个数相同时输出此时的值,暴力跑. 1 #include<cstdio> 2 int main(){ 3 int t,n,a[16]; 4 while(~scanf("%d",&t)){ 5 while(t--){ 6 scanf("%d",&n);

ZOJ Monthly, January 2015 (B、E、G、H)

B题: 先处理出已有卡牌,然后进行dfs,dfs有个很大的剪枝,就是当前位置如果字典序小于了,那么后面就不用继续放了,直接用组合数学进行计算即可,如果大于就不用考虑了,如果等于才继续往后搜,这样的话,搜等于只要在字典序相等的一条路上搜,时间可以接受 E题:模拟即可,不存在无解情况 G题:先全部数字GCD一遍,如果不为1,就是无解,如果为1,那么构造答案,其实只要拿第一个数字,可以其他每个数字做一次gcd,第一个数字就是1了,然后再拿第一个数字和后面数字做gcd,就全部都是1了,一共进行n - 2

ZOJ Monthly, January 2018

A. Candy Game 显然最优策略是一个一个吃,故比较哪种糖果的个数比较多即可. #include<cstdio> int T,n,i,x,sum; int main(){ scanf("%d",&T); while(T--){ scanf("%d",&n); sum=0; for(i=1;i<=n;i++)scanf("%d",&x),sum+=x; for(i=1;i<=n;i++)sca

ZOJ Monthly, January 2018 Solution

A - Candy Game 水. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 1010 5 int t, n; 6 int a[N], b[N]; 7 8 int main() 9 { 10 scanf("%d", &t); 11 while (t--) 12 { 13 scanf("%d", &n); 14 for (int i = 1; i <

[ZOJ]ZOJ Monthly, January 2018

solved 4 rank 1 题挺好的,就是没见过这么卡常的.. A(签到) 题意:有n个盒子,每个盒子里都有若干AB两种糖,甲只能吃A,乙只能吃B,每次至少吃一个,最多把一个盒子里的吃光,没有糖之后就不能吃,吃掉最后一颗糖的获胜,问谁能获胜. 显然一次吃一颗最优,谁的糖多谁赢. #include<bits/stdc++.h> using namespace std; #define rep(i,n) for(int i=1;i<=n;i++) #define LL long long

135 - ZOJ Monthly, August 2014

135 - ZOJ Monthly, August 2014 A:构造问题,推断序列奇偶性.非常easy发现最小值不是1就是0.最大值不是n就是n - 1,注意细节去构造就可以 E:dp.dp[i][j]表示长度i,末尾状态为j的最大值,然后每一个位置数字取与不取,不断状态转移就可以 G:就一个模拟题没什么好说的 H:dfs,每次dfs下去,把子树宽度保存下来,然后找最大值,假设有多个.就是最大值+cnt宽度 I:构造,假设r * 2 > R,肯定无法构造.剩下的就二分底边.按等腰三角形去构造就

ZOJ Monthly, September 2003【部分题解】

今天比赛做了一下这套题目.出了四道.两道水题,两道DP 比赛链接:http://vjudge.net/contest/view.action?cid=51404#problem/B 上来搞了一道水题之后就搞B题 题意很好理解,上来看了一下就懂了.以为是规律有循环节,没看wa那么多毅然决然提交,wa了一发. A = "^__^" and B = "T.T",C = BA = "T.T^__^".然后A=B,B=C,一直重复这个操作,问最后第n位的字

ZOJ Monthly, June 2014——Grouping

题目连接 题意: n个点,m条边 每条边两个整数a.b,表示a到b的有向边 求,至少需要几个集合,使得:每个集合中的元素互相不能到达 N(1≤ N≤ 100000), M(1≤ M≤ 300000) 分析: 相连的两个点不能在同一个集合中,那么,对于一个长度为n的链,至少需要n个集合:如果链中有环,相当于把环展开,这个就需要缩点处理 就是缩点之后求点权最长路 注意:模板中scc_cnt是从1开始的,如果使用缩点后的图,初始化时需要初始化总点数加一 因为总点数有限,用拓扑排序每次删除所有入度为零的

记次浙大月赛 134 - ZOJ Monthly, June 2014

链接 虽做出的很少,也记录下来,留着以后来补..浙大题目质量还是很高的 B 并查集的一些操作,同类和不同类我是根据到根节点距离的奇偶判断的,删点是直接新加一个点,记得福大月赛也做过类似的,并差集的这类关系题目还是比较常见的,有空深究一下. 1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6