A: Little Sub and Pascal's Triangle
Solved.
题意:
求杨辉三角第n行奇数个数
思路:
薛聚聚说找规律,16说Lucas
答案是 $2^p ;;p 为 n - 1 中 以2进制表示下1的个数$
证明
$Ans = sumlimits_0^n C_n^i ;\%; 2 = sumlimits_0^n C_{frac{n}{2}}^{frac{i}{2}} cdot C_{n;\%;2}^{i;\%;2}$
我们考虑 $C_{n ;\%; 2}^{i ;\%; 2}$ 一共有四种取值
$C_0^0 ;; C_0^1;; C_1^0 ;; C_1^1$
我们发现 只有 $C_0^1的值为0 其他三个值都为1$
那么我们再考虑$C_n^i 这个式子$
它通过卢卡斯定理分解 实际上可以写成
我们先假设
$i 以二进制表示为$
$a_1, a_2, cdots a_k$
$n 以二进制表示为$
$b_1, b_2, cdots b_k$
那么 $C_n^i = C_{b_1}^{a_1} cdot C_{b_2}^{a_2} cdots C_{b_k}^{a_k}$
那么我们发现,
要满足$C_n^i;\%; 2 = 1 ;;$
$那么在b_y = 1的位置上,i在对应位置上取0或者1都可以$
在$b_y = 0 的位置上,i在对应位置的取值已经固定 是 0$
那么$i的取值一共有2^p p 为(n - 1)以2进制表示下1的个数$
为什么是$n - 1 ;;因为杨辉三角是从第0行开始的$
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 }
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 }
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 }
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 }
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 }