呃呃这场签到一时半会没写出来就去睡觉了,睡醒已经结束,然后一题没开
更新至L,F,A,J…
(好无聊好无聊好无聊呜呜呜7.30)
题L
题意:给定一个 n∗m 排布的灯,有 q 次操作,每次操作可以 打开/关闭 某具体 行/列 , 问最后有多少灯是打开的(1<=n,m,q<=1e6)。
解:由于后面的操作会对当前操作有影响,所以不妨我们对操作倒着看,这时候第一次打开某一行或列必然是增加答案的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e6 + 10; int row[N], col[N]; struct S{ string x1, x2; int x; }s[N]; int main(){ int n, m, k; cin >> n >> m >> k; ll ans = 0; for(int i = 1; i <= k; ++ i){ cin >> s[i].x1 >> s[i].x >> s[i].x2; } for(int i = k; i >= 1; -- i){ auto t = s[i]; if(t.x1 == "row"){ if(row[t.x] == 0){ row[t.x] = 1; if(t.x2 == "on") ans += m; n --; } }else { if(col[t.x] == 0){ col[t.x] = 1; if(t.x2 == "on") ans += n;; m --; } } } cout << ans; }
|
题F
题意:n 个候选人每人都有一个 ai(political tendencies),有 n−1 轮投票,每轮投票中未出局的候选人可以给一个人投票,票数最多者出局,其中对于 i 这个候选人而言,他会投给 j 候选人,当且仅当存在最大的 ∣ai−aj∣, 如果同时存在了两个相同最大值的∣ai−aj∣ , 那么优先投给aj 较大的人。问最后剩下来的是几号候选人。
解:由题意可得,每轮出局的必然是剩余候选人中 ai 值是 最大/最小, 那么我们可以对 ai 排完序后对两端用双指针,将两个指针与中间候选人的 amid 进行比较。 最终复杂度为 O(n)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e6 + 10; pair<int, int> p[N]; int main(){ int n; cin >> n; for(int i = 1; i <= n; ++ i){ int x; cin >> x; p[i] = {x, i}; } sort(p + 1, p + 1 + n); int l = 1, r = n; while(l < r){ int mid = l + r >> 1; if(2 * p[mid].first > p[l].first + p[r].first) l ++; else r --; } cout << p[l].second; }
|
题A
题意:已知一个消息字符串 s, 其加密字符串为 t+s+t,其中字符串 t 为识别字符串,用于解码。但对于本题中读取加密字符串是一个个字符读取,当加密字符串 0101101010, 已知t=010, 其标准的消息字符串 s=1101, 但由于读取过程的问题,在计算机读取了加密字符到 01011010 时就会停止并且获得消息字符串 s=11 与需求不符,存在歧义。 题目给定消息字符串 s 的长度和识别字符串 t,要求任意构造一个不存在歧义的消息字符串 s(1<=∣t∣,n<=1000, 本题中字符串由 01 构成)。
解:由于可以任意构造且字符串的长度很小,而且我们是知道识别字符串 t的, 那么首先要使得 s中不存在 t,我们可以直接假设 s 全为 0, 用 find 函数查看是否存在歧义,存在则用全 1 代替。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 2e5 + 10; void solve(){ int n, f = 0; string t; cin >> n >> t; string x = t; for(int i = 1; i <= n; ++ i) x = x + "0"; x = x + t; if(x.find(t, 1) != x.size() - t.size()) f = 1; for(int i = 1; i <= n; ++ i) cout << f; cout << '\n'; } int main(){ int T; cin >> T; while(T --) solve(); }
|
题J
题意:给定整数 n 和 m,要求构造长度为 n 的数组 a,其中 −m<=ai<=m, 对任意 2<=k<=n,满足连续 k 个元素和 >=0,问存在多少种构造情况(1<=n,m<=5000,答案模998244252)
解:用 dp[i][j] 表示前 i 个元素种包含第 i 个元素最小和为 j 的情况数。我们再用一个 sum[i][j] 表示包含第 i 个元素和为 j 的情况数,这样我们对和从大到小枚举,就 O(n∗m) 跑过。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| #include<iostream> using namespace std; const int N = 5010, MOD = 998244353; int dp[N][N + N], sum[N][N + N]; int main(){ int n, m; cin >> n >> m; for(int i = m; i >= -m; -- i) { sum[1][i + N] = 1; dp[1][i + N] = dp[1][i + N + 1] + sum[1][i + N]; } for(int i = 2; i <= n; ++ i){ for(int j = m; j >= -m; -- j){ if(j >= 0) sum[i][j + N] = dp[i - 1][j + N - m]; else sum[i][j + N] = dp[i - 1][N - j]; dp[i][j + N] = (dp[i][j + N + 1] + sum[i][j + N]) % MOD; } } cout << dp[n][N - m]; }
|