牛客暑期多校训练营4
发表于:2023-07-28 | 分类: 思维
字数统计: 1.4k | 阅读时长: 6分钟 | 阅读量:

呃呃这场签到一时半会没写出来就去睡觉了,睡醒已经结束,然后一题没开
更新至L,F,A,J…
(好无聊好无聊好无聊呜呜呜7.30)

题L

题意:给定一个 nmn * m 排布的灯,有 qq 次操作,每次操作可以 打开/关闭打开/关闭 某具体 /行/列 , 问最后有多少灯是打开的(1<=n,m,q<=1e61<=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

题意:nn 个候选人每人都有一个 ai(politicala_i (political tendencies)tendencies),有 n1n - 1 轮投票,每轮投票中未出局的候选人可以给一个人投票,票数最多者出局,其中对于 ii 这个候选人而言,他会投给 jj 候选人,当且仅当存在最大的 aiaj|a_i - a_j|, 如果同时存在了两个相同最大值的aiaj|a_i - a_j| , 那么优先投给aja_j 较大的人。问最后剩下来的是几号候选人。

解:由题意可得,每轮出局的必然是剩余候选人中 aia_i 值是 最大/最小最大/最小, 那么我们可以对 aia_i 排完序后对两端用双指针,将两个指针与中间候选人的 amida_{mid} 进行比较。 最终复杂度为 O(n)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

题意:已知一个消息字符串 ss, 其加密字符串为 t+s+tt+s+t,其中字符串 tt 为识别字符串,用于解码。但对于本题中读取加密字符串是一个个字符读取,当加密字符串 01011010100101101010, 已知t=010t=010, 其标准的消息字符串 s=1101s=1101, 但由于读取过程的问题,在计算机读取了加密字符到 0101101001011010 时就会停止并且获得消息字符串 s=11s=11 与需求不符,存在歧义。 题目给定消息字符串 ss 的长度和识别字符串 tt,要求任意构造一个不存在歧义的消息字符串 ss1<=t,n<=10001<=|t|, n<=1000, 本题中字符串由 0101 构成)。

解:由于可以任意构造且字符串的长度很小,而且我们是知道识别字符串 tt的, 那么首先要使得 ss中不存在 tt,我们可以直接假设 ss 全为 00, 用 findfind 函数查看是否存在歧义,存在则用全 11 代替。

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

题意:给定整数 nnmm,要求构造长度为 nn 的数组 aa,其中 m<=ai<=m-m<=a_i<=m, 对任意 2<=k<=n2<=k<=n,满足连续 kk 个元素和 >=0>=0,问存在多少种构造情况(1<=n,m<=5000,答案模998244252)(1<=n,m<=5000, 答案模998244252)

解:用 dp[i][j]dp[i][j] 表示前 ii 个元素种包含第 ii 个元素最小和为 jj 的情况数。我们再用一个 sum[i][j]sum[i][j] 表示包含第 ii 个元素和为 jj 的情况数,这样我们对和从大到小枚举,就 O(nm)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];
}
上一篇:
牛客暑期多校训练营5
下一篇:
牛客暑期多校训练营3