ZOJ Monthly, March 2018 Solution
A - Easy Number Game
水。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 100010 6 ll arr[N]; 7 int n, m; 8 9 int main() 10 { 11 int t; scanf("%d", &t); 12 while (t--) 13 { 14 scanf("%d%d", &n, &m); 15 for (int i = 1; i <= n; ++i) scanf("%lld", arr + i); 16 sort(arr + 1, arr + 1 + n); 17 ll res = 0; 18 for (int i = 1; i <= m; ++i) 19 res += arr[i] * arr[2 * m - i + 1]; 20 printf("%lld\n", res); 21 } 22 return 0; 23 }
B - Lucky Man
题意:判断大数开根后的奇偶性
思路:牛顿迭代法
1 import java.io.BufferedInputStream; 2 import java.util.Scanner; 3 import java.math.*; 4 5 public class Main { 6 7 public static void main(String[] args) { 8 Scanner in = new Scanner(new BufferedInputStream(System.in)); 9 int t = in.nextInt(); 10 BigInteger a, x, two; String n; 11 two = BigInteger.valueOf(2); 12 while (t-- != 0) 13 { 14 n = in.next(); 15 a = new BigInteger(n); 16 x = new BigInteger(n.substring(0, n.length() / 2 + 1)); 17 while (a.compareTo(x.multiply(x)) < 0) 18 x = x.add(a.divide(x)).divide(two); 19 if (x.mod(two).compareTo(BigInteger.ZERO) == 0) System.out.println(0); 20 else System.out.println(1); 21 } 22 in.close(); 23 } 24 }
C - Travel along the Line
题意:一维坐标系中,刚开始位于原点,有$\frac{1}{4}$的概率 坐标 +1 和 -1 有$\frac {1}{2} 的概率 不动$ 求在第n秒的时候恰好到达第m个位置的概率
思路:考虑把一个0拆成两个0,变成四种操作,这样四种操作是等概率的,那么所有的可能性就是 $4^n$ 再考虑符合条件的方案数
可以考虑将m通过坐标变换转化成正的,那么一个满足题意的操作序列肯定是 1 的个数 减去 -1的 个数 恰好为m
那么我们只需要枚举1的个数,排列组合一下即可
16说 假如用a 表示 1 的个数 b 表示 -1 的个数 c 表示 0的个数
那么有$\frac {n!} {a! \cdot b! \cdot c!}$ 但是这里要考虑 多乘上$2^c$ 因为每个0都有两种选择 ,可以是$0_1 或者 是 0_2$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 100010 6 ll MOD = (ll)1e9 +7; 7 8 ll fac[N], Bit[N]; 9 ll qmod(ll base, ll n) 10 { 11 ll res = 1; 12 while (n) 13 { 14 if (n & 1) res = res * base % MOD; 15 base = base * base % MOD; 16 n >>= 1; 17 } 18 return res; 19 } 20 21 void Init() 22 { 23 fac[0] = 1; 24 Bit[0] = 1; 25 for (int i = 1; i < N; ++i) fac[i] = fac[i - 1] * i % MOD; 26 for (int i = 1; i < N; ++i) Bit[i] = Bit[i - 1] * 2 % MOD; 27 } 28 29 int n, m; 30 31 int main() 32 { 33 Init(); 34 int t; scanf("%d", &t); 35 while (t--) 36 { 37 scanf("%d%d", &n, &m); 38 if (m < 0) m = -m; 39 ll p = 0, q = qmod(4, n); 40 for (int i = 0; 2 * i + m <= n; ++i) 41 p = (p + (fac[n] * qmod(fac[i], MOD - 2) %MOD * qmod(fac[i + m], MOD - 2) % MOD * qmod(fac[n - 2 * i - m], MOD - 2) % MOD * Bit[n - 2 * i - m] % MOD)) % MOD; 42 ll res = p * qmod(q, MOD - 2) % MOD; 43 printf("%lld\n", res); 44 } 45 return 0; 46 }
D - Machine Learning on a Tree
留坑。
E - Yet Another Tree Query Problem
题意:每次询问$[l, r]$ 区间内所有点所在的连通块个数
思路:先预处理l 为 1 r 为 1 ->n 的答案 考虑删去一个点对后面答案的影响
将一个点的所有孩子和父亲中,按编号排序
比如说 点1 连出去的边有 4, 10, 20
那么 对于右界为 2-3 的 连通块个数少一
右界为5 - 9 的 连通块个数不变
右界为 11 - 19 的 连通块个数加1
BIT区间更新即可
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 200010 5 #define pii pair <int, int> 6 int t, n, q; 7 vector <int> G[N]; 8 vector <pii> que[N]; 9 int base[N], ans[N]; 10 11 struct BIT 12 { 13 int a[N]; 14 void init() { memset(a, 0, sizeof a); } 15 void update(int x, int val) { for (; x <= n; x += x & -x) a[x] += val; } 16 void update(int l, int r, int val) 17 { 18 if (r < l) return; 19 update(l, val); 20 update(r + 1, -val); 21 } 22 int query(int x) 23 { 24 int res = 0; 25 for (; x; x -= x & -x) 26 res += a[x]; 27 return res; 28 } 29 30 }bit; 31 32 void Run() 33 { 34 scanf("%d", &t); 35 while (t--) 36 { 37 for (int i = 1; i <= n; ++i) G[i].clear(), que[i].clear(); 38 bit.init(); 39 scanf("%d%d", &n, &q); 40 for (int i = 1, u, v; i < n; ++i) 41 { 42 scanf("%d%d", &u, &v); 43 G[u].push_back(v); 44 G[v].push_back(u); 45 } 46 for (int i = 1, l, r; i <= q; ++i) 47 { 48 scanf("%d%d", &l, &r); 49 que[l].emplace_back(r, i); 50 } 51 for (int i = 1; i <= n; ++i) 52 { 53 int tmp = 1; 54 sort(G[i].begin(), G[i].end()); 55 for (auto v : G[i]) if (v < i) 56 --tmp; 57 base[i] = base[i - 1] + tmp; 58 } 59 for (int i = 1; i <= n; ++i) 60 { 61 for (auto it : que[i]) 62 ans[it.second] = base[it.first] + bit.query(it.first); 63 G[i].push_back(n + 1); 64 int pre = i + 1; 65 for (int j = 0, len = G[i].size(), add = -1; j < len; ++j) 66 { 67 int v = G[i][j]; 68 if (v < i) continue; 69 bit.update(pre, v - 1, add); 70 pre = v; ++add; 71 } 72 } 73 for (int i = 1; i <= q; ++i) printf("%d\n", ans[i]); 74 } 75 } 76 77 int main() 78 { 79 #ifdef LOCAL 80 freopen("Test.in", "r", stdin); 81 #endif 82 83 Run(); 84 return 0; 85 86 }
F - And Another Data Structure Problem
题意:两种操作,一种是区间立方,一种是区间求和
思路:考虑这个模数很特殊
$3^{48} \equiv 1 \pmod {99970}$
所以有
$a^{3^{48}} \equiv a \pmod {99971}$
所有任意数做48次后 必然会回到原数 考虑开48棵线段树解决
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 #define ll long long 6 const ll MOD = 99971; 7 int t, n, q; 8 ll arr[N]; 9 10 struct SEG 11 { 12 ll a[N << 2][49], tmp[49]; 13 int lazy[N << 2]; 14 void init() { memset(a, 0, sizeof a); } 15 void pushup(int id) 16 { 17 for (int i = 0; i < 48; ++i) 18 a[id][i] = (a[id << 1][(i + lazy[id << 1]) % 48] + a[id << 1 | 1][(i + lazy[id << 1 | 1]) % 48]) % MOD; 19 } 20 void pushdown(int id) 21 { 22 if (!lazy[id]) return; 23 lazy[id << 1] = (lazy[id << 1] + lazy[id]) % 48; 24 lazy[id << 1 | 1] = (lazy[id << 1 | 1] + lazy[id]) % 48; 25 for (int i = 0; i < 48; ++i) tmp[i] = a[id][(i + lazy[id]) % 48]; 26 memcpy(a[id], tmp, sizeof tmp); 27 lazy[id] = 0; 28 } 29 void build(int id, int l, int r) 30 { 31 lazy[id] = 0; 32 if (l == r) 33 { 34 a[id][0] = arr[l]; 35 for (int i = 1; i < 48; ++i) 36 a[id][i] = a[id][i - 1] * a[id][i - 1] % MOD * a[id][i - 1] % MOD; 37 return; 38 } 39 int mid = (l + r) >> 1; 40 build(id << 1, l, mid); 41 build(id << 1 | 1, mid + 1, r); 42 pushup(id); 43 } 44 void update(int id, int l, int r, int ql, int qr, int val) 45 { 46 if (l >= ql && r <= qr) 47 { 48 lazy[id] = (lazy[id] + val) % 48; 49 return; 50 } 51 pushdown(id); 52 int mid = (l + r) >> 1; 53 if (ql <= mid) update(id << 1, l, mid, ql, qr, val); 54 if (qr > mid) update(id << 1 | 1, mid + 1, r, ql, qr, val); 55 pushup(id); 56 } 57 ll query(int id, int l, int r, int ql, int qr) 58 { 59 if (l >= ql && r <= qr) return a[id][lazy[id]]; 60 pushdown(id); 61 int mid = (l + r) >> 1; 62 ll res = 0; 63 if (ql <= mid) res = (res + query(id << 1, l, mid, ql, qr)) % MOD; 64 if (qr > mid) res = (res + query(id << 1 | 1, mid + 1, r, ql, qr)) % MOD; 65 //pushup(id); 66 return res; 67 } 68 }seg; 69 70 void Run() 71 { 72 scanf("%d", &t); 73 while (t--) 74 { 75 scanf("%d%d", &n, &q); 76 for (int i = 1; i <= n; ++i) scanf("%lld", arr + i), arr[i] %= MOD; 77 seg.build(1, 1, n); 78 for (int i = 1, op, l, r; i <= q; ++i) 79 { 80 scanf("%d%d%d", &op, &l, &r); 81 if (op == 1) seg.update(1, 1, n, l, r, 1); 82 else printf("%lld\n", seg.query(1, 1, n, l, r)); 83 } 84 } 85 } 86 87 int main() 88 { 89 #ifdef LOCAL 90 freopen("Test.in", "r", stdin); 91 #endif 92 93 Run(); 94 return 0; 95 96 }
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 #define ll long long 6 const ll MOD = 99971; 7 int t, n, q; 8 ll arr[N]; 9 10 struct SEG 11 { 12 ll a[N << 2][50], tmp[50]; 13 int lazy[N << 2]; 14 void pushup(int id) 15 { 16 for (int i = 0; i < 48; ++i) 17 a[id][i] = (a[id << 1][(i + lazy[id << 1]) % 48] + a[id << 1 | 1][(i + lazy[id << 1 | 1]) % 48]) % MOD; 18 } 19 void build(int id, int l, int r) 20 { 21 lazy[id] = 0; 22 if (l == r) 23 { 24 a[id][0] = arr[l]; 25 for (int i = 1; i < 48; ++i) 26 a[id][i] = a[id][i - 1] * a[id][i - 1] % MOD * a[id][i - 1] % MOD; 27 return; 28 } 29 int mid = (l + r) >> 1; 30 build(id << 1, l, mid); 31 build(id << 1 | 1, mid + 1, r); 32 pushup(id); 33 } 34 void update(int id, int l, int r, int ql, int qr, int val) 35 { 36 if (l >= ql && r <= qr) 37 { 38 lazy[id] = (lazy[id] + 1) % 48; 39 return; 40 } 41 int mid = (l + r) >> 1; 42 if (ql <= mid) update(id << 1, l, mid, ql, qr, val); 43 if (qr > mid) update(id << 1 | 1, mid + 1, r, ql, qr, val); 44 pushup(id); 45 } 46 ll query(int id, int l, int r, int ql, int qr, int k = 0) 47 { 48 k = (k + lazy[id]) % 48; 49 if (l >= ql && r <= qr) return a[id][k]; 50 int mid = (l + r) >> 1; 51 ll res = 0; 52 if (ql <= mid) res = (res + query(id << 1, l, mid, ql, qr, k)) % MOD; 53 if (qr > mid) res = (res + query(id << 1 | 1, mid + 1, r, ql, qr, k)) % MOD; 54 return res; 55 } 56 }seg; 57 58 void Run() 59 { 60 scanf("%d", &t); 61 while (t--) 62 { 63 scanf("%d%d", &n, &q); 64 for (int i = 1; i <= n; ++i) scanf("%lld", arr + i), arr[i] %= MOD; 65 seg.build(1, 1, n); 66 for (int i = 1, op, l, r; i <= q; ++i) 67 { 68 scanf("%d%d%d", &op, &l, &r); 69 if (op == 1) seg.update(1, 1, n, l, r, 1); 70 else printf("%lld\n", seg.query(1, 1, n, l, r)); 71 } 72 } 73 } 74 75 int main() 76 { 77 #ifdef LOCAL 78 freopen("Test.in", "r", stdin); 79 #endif 80 81 Run(); 82 return 0; 83 84 }
G - Neighboring Characters
留坑。
H - Happy Sequence ZOJ
题意:用1-n的数,每个数可以用无限次,组成长度为m的序列,求有多少个序列满足 $gcd(b_i, b_{i +1}) = b_{i}$
思路:考虑枚举序列里面不同的数的个数,根据题目范围,最多有10个不同的数,然后隔板法求方案数
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 long long f[15]; 6 long long C[15]; 7 long long MOD; 8 int p[15]; 9 int n, m; 10 11 void dp(int t) { 12 int j; 13 j = 2; 14 while (p[t - 1] * j <= n) { 15 p[t] = p[t - 1] * j; 16 f[t]++; 17 dp(t + 1); 18 j++; 19 } 20 } 21 22 ll qmod(ll base, ll n) 23 { 24 ll res = 1; 25 while (n) 26 { 27 if (n & 1) res = res * base % MOD; 28 base = base * base % MOD; 29 n >>= 1; 30 } 31 return res; 32 } 33 34 int main() 35 { 36 int i, j, t; 37 long long ans; 38 scanf("%d", &t); 39 MOD = 1000000007; 40 while (t--) { 41 scanf("%d %d", &n, &m); 42 memset(f, 0, sizeof f); 43 memset(p, 0, sizeof p); 44 ans = 0; 45 C[0] = 1; 46 for (i = 1; i <= 11 ; ++i) 47 C[i] = (C[i - 1] * (m - i) % MOD * qmod(i, MOD - 2)) % MOD; 48 for (i = 1; i <= n; ++i) { 49 p[1] = i; 50 ++f[1]; 51 dp(2); 52 } 53 for (i = 1; i <= 11; ++i) { 54 ans = (ans + f[i] * C[i - 1] % MOD) % MOD; 55 } 56 printf("%lld\n",ans); 57 } 58 return 0; 59 }
I - Your Bridge is under Attack
留坑。
J - Super Brain
水。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 int n; 6 int cnt[N * 10], a[N], b[N]; 7 8 int main() 9 { 10 int t; scanf("%d", &t); 11 while (t--) 12 { 13 scanf("%d", &n); 14 for (int i = 1; i <= n; ++i) scanf("%d", a + i); 15 for (int i = 1; i <= n; ++i) scanf("%d", b + i); 16 memset(cnt, 0, sizeof cnt); 17 for (int i = 1; i <= n; ++i) ++cnt[a[i]]; 18 int res = 0; 19 for (int i = 1; i <= n; ++i) if (cnt[b[i]] == 1) 20 { 21 res = b[i]; 22 break; 23 } 24 printf("%d\n", res); 25 } 26 return 0; 27 }