2021CCPC northeast four provinces competition
A. Matrix
General meaning
You need to use [ 1 , n 2 ] [1, n^2] All numbers of [1,n2] to fill one n × n n \times n n × Matrix of n
definition a [ ] a[] a [], where a i a_i ai , is the second in the matrix i i The minimum value in line i definition S = { a 1 , a 2 , . . . , a n } ∩ { 1 , 2 , . . . , n } S = \{ a_1, a_2, ..., a _n\} \cap \{ 1, 2, ..., n\} S={a1,a2,...,an}∩{1,2,...,n}.
We need to calculate for all cases ∑ ∣ S ∣ \sum|S| ∑∣S∣. last m o d 998244353 \mod998244353 mod998244353 outputs the answer
Problem solving ideas
thinking
We consider that the number range that can produce contribution is [ 1 , n ] [1, n] [1,n], so we might as well calculate the contribution of each number, and then add it
Assuming current considerations m m m, then for m m m we can start from n n Select a row from the n rows, and for the remaining n − 1 n - 1 n − 1 numbers, should be greater than m m m, so the choice is C n 2 − m n − 1 C_{n^2 - m}^{n - 1} Cn2 − mn − 1, and the numbers of this line can be arranged arbitrarily. The situation is n ! n! n!. The remaining numbers can be arranged arbitrarily ( n 2 − n ) ! (n^2 - n)! (n2−n)!
So eventually m m m's contribution is: n × C n 2 − m n − 1 × n ! × ( n 2 − n ) ! n \times C_{n^2 - m}^{n - 1} \times n! \times (n^2 - n)! n×Cn2−mn−1×n!×(n2−n)!
(PS: teammates also came up with another way to calculate, formula: n 2 × ( n 2 − m ) ! × A n 2 − n m − 1 n^2 \times (n^2 - m)! \times A_{n^2-n}^{m-1} n2×(n2−m)!×An2−nm−1)
We just need to enumerate m ∈ [ 1 , n ] m \in [1, n] m ∈ [1,n], and then accumulate the results
AC code
#include <bits/stdc++.h> #define rep(i, n) for (int i = 1; i <= (n); ++i) using namespace std; typedef long long ll; const int N = 5E3 + 10, M = N * N, mod = 998244353; int fpow(int a, int b) { ll res = 1; a %= mod; while (b) { if (b & 1) res = res * a % mod; b >>= 1; a = 1ll * a * a % mod; } return res; } int num[M], innum[M]; void init(int n = M - 5) { num[0] = innum[0] = 1; for (int i = 1; i <= n; ++i) { num[i] = 1ll * num[i - 1] * i % mod; } innum[n] = fpow(num[n], mod - 2) % mod; for (int i = n - 1; i >= 1; i--) { innum[i] = 1ll * innum[i + 1] * (i + 1) % mod; } } int C(int a, int b) { return 1ll * num[a] * innum[a - b] % mod * innum[b] % mod; } int main() { init(); int t; scanf("%d", &t); while (t--) { ll n; scanf("%lld", &n); ll res = 0; rep(i, n) { res = (res + n * C(n * n - i, n - 1) % mod * num[n] % mod * num[n * n - n]) % mod; } printf("%lld\n", res); } return 0; }
C. Vertex Deletion
https://blog.csdn.net/qq_49494204/article/details/120112398
D. Lowbit
General meaning
Given a length of n n Sequence of n a [ ] a[] a [], there are two operations:
1 l r for [ l , r ] [l, r] Each number of [l,r] a i a_i ai, add it all l o w b i t ( a i ) lowbit(a_i) lowbit(ai).
2 l r query [ l , r ] [l, r] Interval sum of [l,r] intervals
Problem solving ideas
Segment tree
First of all, after reading this topic, we can easily think that this is the interval operation of line segment tree
Considering the complex modification operations, compared with the usual interval modification, adding lowbit to each position seems to be impossible to maintain directly through calculation
So we thought
x
+
l
o
w
b
i
t
(
x
)
x + lowbit(x)
Properties of x+lowbit(x) We found that if
x
∈
{
2
of
whole
second
power
}
The entire power of x \in \{2 \}
The entire power} of x ∈ {2 is equivalent to each operation,
x
=
x
×
2
x = x \times 2
x=x×2.
Let's consider that for a number
x
x
For x, it will add at most
l
o
g
x
logx
logx times
l
o
w
b
i
t
(
x
)
lowbit(x)
lowbit(x), so that
x
′
∈
{
2
of
whole
second
power
}
X '\ in \ {integral power of 2 \}
The integral power of x ′∈ {2}
Therefore, we conclude that for positions that are not an integral power of 2, we carry out violent modification, and the total complexity of violent modification is O ( n l o g ∣ a i ∣ ) O(nlog|a_i|) O(nlog∣ai∣). For the position that is the integral power of 2, we can multiply the interval by 2
The information to be maintained in the tree: interval sum, whether the elements in the interval are the integral power of 2, and interval multiplication
AC code
#include <bits/stdc++.h> #define rep(i, n) for (int i = 1; i <= (n); ++i) using namespace std; typedef long long ll; const int N = 1E5 + 10, mod = 998244353; int lowbit(int x) { return x & -x; } bool judge(int x) { return bitset<32>(x).count() == 1; } int w[N]; struct node { int l, r; ll sum; bool flag; int lazy; }t[N << 2]; void pushdown(node& op, int lazy) { op.lazy = 1ll * op.lazy * lazy % mod; op.sum = (op.sum * lazy) % mod; } void pushdown(int x) { if (t[x].lazy == 1) return; pushdown(t[x << 1], t[x].lazy), pushdown(t[x << 1 | 1], t[x].lazy); t[x].lazy = 1; } void pushup(int x) { t[x].sum = (t[x << 1].sum + t[x << 1 | 1].sum) % mod; t[x].flag = t[x << 1].flag and t[x << 1 | 1].flag; } void build(int l, int r, int x = 1) { t[x] = { l, r, w[l], 0, 1 }; if (l == r) { t[x].flag = judge(w[l]); return; } int mid = l + r >> 1; build(l, mid, x << 1), build(mid + 1, r, x << 1 | 1); pushup(x); } void modify(int l, int r, int x = 1) { if (l <= t[x].l and r >= t[x].r) { if (t[x].flag) { //The intervals are all integral powers of 2, multiplied directly by 2 pushdown(t[x], 2); return; } if (t[x].l == t[x].r) { t[x].sum += lowbit(t[x].sum); t[x].flag = judge(t[x].sum); return; } } pushdown(x); int mid = t[x].l + t[x].r >> 1; if (l <= mid) modify(l, r, x << 1); if (r > mid) modify(l, r, x << 1 | 1); pushup(x); } ll ask(int l, int r, int x = 1) { if (l <= t[x].l and r >= t[x].r) return t[x].sum; pushdown(x); int mid = t[x].l + t[x].r >> 1; ll res = 0; if (l <= mid) res = ask(l, r, x << 1); if (r > mid) res = (res + ask(l, r, x << 1 | 1)) % mod; return res; } int main() { int T; cin >> T; while (T--) { int n; scanf("%d", &n); rep(i, n) scanf("%d", &w[i]); build(1, n); int m; scanf("%d", &m); while (m--) { int tp, l, r; scanf("%d %d %d", &tp, &l, &r); if (tp == 1) modify(l, r); else printf("%lld\n", ask(l, r)); } } return 0; }
E. Easy Math Problem
General meaning
Given number a a a. Ask if you can find one b b b. Make b b b yes a a Multiple of a, and b b b can be expressed as b = x + y + z b = x + y + z b=x+y+z, where x , y , z x, y, z x. Y, Z is b b Different factors of b
Problem solving ideas
order b = 6 a b = 6a b=6a, then b = a + 2 a + 3 a b = a + 2a + 3a b=a+2a+3a.
AC code
#include <bits/stdc++.h> #define rep(i, n) for (int i = 1; i <= (n); ++i) using namespace std; typedef long long ll; int main(void) { int t; cin >> t; while (t--) { ll n; scanf("%lld", &n); n *= 6; printf("%lld 3\n", n); printf("%lld %lld %lld\n", n / 6, n / 3, n / 2); } return 0; }
I. Takeaway
No, it's too difficult
K. City
General meaning
give n n n points, m m m undirected edges, q q q questions
Each edge has a weight w w w. Delete ownership value less than p p After the edge of p, the number of nodes that can reach each other in all the remaining nodes in the graph
Problem solving ideas
thinking
Firstly, considering that all edges are undirected, if a block is connected, all nodes in the block can reach each other The resulting contributions are: C n 2 , n by block large Small C_ N ^ 2, where n is the block size Cn2, n is the block size
Therefore, for each query, I know that I need to know how many connected blocks there are and the size of each connected block
Concurrent query + offline query
We consider using union search set to maintain connected block information
Because it is
q
q
q queries, if we maintain the connected block information every time, the complexity will be
O
(
m
q
l
o
g
n
)
O(mqlogn)
O(mqlogn).
We consider taking queries offline and sorting them from large to small Initially, it was considered that the graph was only n n Empty graph of n points, set the current query as p i p_i pi, we put all the edge weights w i ≥ p i w_i \ge p_i Edges with wi ≥ pi , are added to the graph
If we sort from small to large, we should initially think that m edges exist in the graph, and each time we delete less than p i p_i pi , the edge of the Because it is not easy to delete the merge set, we consider sorting from large to small
Consider how to maintain the added answer contribution s u m sum sum:
First, for the initial empty graph, s u m = 0 sum = 0 sum=0. When we merge two connected blocks a a a and b b b, we can first subtract the contribution of the original two connected blocks, and then add the contribution of the combined new connected blocks
AC code
#include <bits/stdc++.h> #define rep(i, n) for (int i = 1; i <= (n); ++i) using namespace std; typedef pair<int, int> PII; typedef long long ll; const int N = 1E5 + 10; int p[N], cou[N]; int find(int x) { return x == p[x] ? x : p[x] = find(p[x]); } ll res[N * 2]; //So the 2E5 asked why the upper limit is only 1E5 ll sum = 0; inline ll fact(ll x) { return x * (x - 1) / 2; } //Calculate C(n, 2) void add(int a, int b) { a = find(a), b = find(b); if (a == b) return; sum = sum - fact(cou[a]) - fact(cou[b]); cou[a] += cou[b], p[b] = a; sum += fact(cou[a]); } int main() { int t; cin >> t; while (t--) { sum = 0; int n, m, q; scanf("%d %d %d", &n, &m, &q); rep(i, n) p[i] = i, cou[i] = 1; //dsu init map<int, vector<PII>, greater<>> edge; //Omit discretization rep(i, m) { int a, b, c; scanf("%d %d %d", &a, &b, &c); edge[c].push_back({ a, b }); } vector<PII> v; rep(i, q) { int k; scanf("%d", &k); v.push_back({ k, i }); } sort(v.begin(), v.end(), greater<>()); auto it = edge.begin(); for (auto& [val, id] : v) { while (it != edge.end() and it->first >= val) { for (auto& [a, b] : it->second) { add(a, b); } ++it; } res[id] = sum; } rep(i, q) printf("%lld\n", res[i]); } return 0; }
M. Master of Shuangpin
General meaning
Simulated double spelling
Problem solving ideas
Simulate according to the requirements of the topic
AC code
#include <bits/stdc++.h> #define rep(i, n) for (int i = 1; i <= (n); ++i) using namespace std; typedef long long ll; const int N = 1005; char s[N]; unordered_map<string, char> mp = { { "iu", 'q' }, { "ei", 'w' }, { "uan", 'r' }, { "ue", 't' }, { "un", 'y' }, { "sh", 'u' }, { "ch", 'i' }, { "uo", 'o' }, { "ie", 'p' }, { "ong", 's' }, { "iong", 's' }, { "ai", 'd' }, { "en", 'f' }, { "eng", 'g' }, { "ang", 'h' }, { "an", 'j' }, { "uai", 'k' }, { "ing", 'k' }, { "uang", 'l' }, { "iang", 'l' }, { "ou", 'z' }, { "ia", 'x' }, { "ua", 'x' }, { "ao", 'c' }, { "zh", 'v' }, { "ui", 'v' }, { "in", 'b' }, { "iao", 'n' }, { "ian", 'm' } }; int main() { for (char c = 'a'; c <= 'z'; ++c) { string ss(1, c); mp[ss] = c; } while (~scanf("%s", s + 1)) { int n = strlen(s + 1); if (n == 1) printf("%c%c", s[1], s[1]); else if (n == 2) printf("%s", s + 1); else { string str = s + 1; if (mp.count(str)) { printf("%c%c", str[0], mp[str]); } else { string a; for (int i = 0; i < str.size() - 1; ++i) { a += str[i]; string b = str.substr(i + 1); if (mp.count(a) and mp.count(b)) { printf("%c%c", mp[a], mp[b]); break; } } } } putchar(getchar()); } return 0; }