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

更新至G,D,C,H…

题G

题意:给定一个只包含 1,2,3,41,2,3,4 的长度为 nn 的数组 aa 和整数 kk, 求包含 1,2,3,41,2,3,4 且有 kk44 的最短连续区间长度。

解:双指针。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;
int a[N], p[5];
int main(){
int n, k, num = 0; cin >> n >> k;
for(int i = 1; i <= n; ++ i) cin >> a[i];
int ans = n;
for(int l = 1, r = 1; r <= n; ++ r){
p[a[r]] ++;
while(p[1] >= 1 && p[2] >= 1 && p[3] >= 1 && p[4] >= k && l <= r){
ans = min(ans, r - l + 1);
p[a[l]] --;
l ++;
}
}
cout << ans;
}

用map wa了一发,奇奇怪怪。

题D

题意:给定 k,c,nk,c,n (1<=k,c,n<=1e9)(1<=k,c,n<=1e9), 求有多少对正整数 aba,b 满足 ka+b=cka+b=c 其中 c=xbx>=1,gcd(a,b)>=nc=xb,x>=1,gcd(a,b)>=n

解:由题意可得方程 a=(cb)/ka=(c-b)/k, 我们由 c=xb,x>=1c=xb, x>=1 可以枚举 bb,复杂度为 O(sqrt(c))O(sqrt(c)), 然后欧几里得判断。

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
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, MOD = 1e9 + 7;
vector<int> prime;
void cal(int x){
for(int i = 1; i <= x / i; ++ i){
if(x % i == 0){
prime.push_back(i);
if(x / i != i) prime.push_back(x / i);
}
}
}
void solve(){
prime.clear();
int k, c, n, ans = 0; cin >> k >> c >> n;
cal(c);
for(auto &b: prime){
if((c - b) % k == 0){
int a = (c - b) / k;
if(a > 0 && __gcd(a, b) >= n) ans ++;
}
}
cout << ans << '\n';
}
int main(){
//ios::sync_with_stdio(0); cin.tie(0);
int n; cin >> n;
while(n--) solve();
return 0;
}

题C

题意:给定一个二分图,图左右两边都有 nn 个点,且点的编号是 1n1-nn+12nn + 1-2n,若 (i,j+n)(i,j + n)之间存在边,则 (j,i+n)(j,i +n)之间不存在边。邻接矩阵给出该图的 n(n1)/2n(n-1)/2条边。问该图的最大匹配 (1<=n<=3000)(1<=n<=3000)

解:根据题目性质,可以将 (i,j+n)(i,j+n) 转换为 (i,j)(i,j),此时该图变成了一个竞赛图,当且仅当一个强连通分量只有两个点的时候答案为 n1n-1,反之为 nn

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;
int d[3010];
int main(){
ios::sync_with_stdio(0); cin.tie(0);
int n, x = 0, y = 0; cin >> n;
for(int i = 1; i <= n; ++ i){
for(int j = 1; j <= n; ++ j){
int x; cin >> x;
if(x) d[i] ++;
}
}
sort(d + 1, d + 1 + n);
for(int i = 1, j = 0, s = 0; i <= n; ++ i){
s += d[i];
if(s == i * (i - 1) / 2){
if(i - j <= 2){cout << n - 1; return 0;}
j = i;
}
}
cout << n;
}

题H

题意:由 nn 个奶酪,体积分别为 aia_i,价值为 bib_i,只能按从前往后的顺序拿,当且仅当第 ii 个奶酪被损坏或者拿走才能对第 i+1i+1 奶酪操作。一共由 mm 个背包,每个背包体积为 wiw_i,每次拿一个背包从第一个奶酪出发,问最多拿走多少价值的奶酪(1<=n<=200,1<=m<=1e5,1<=ai<=200,1<=bi<=1e5,1<=wi<=200)(1<=n<=200,1<=m<=1e5,1<=a_i<=200,1<=b_i<=1e5,1<=w_i<=200)

解:我们用 dp[i][j]dp[i][j] 表示用到第 ii 个背包花费 jj 空间的最大价值。因为背包是连续使用的,并且题目给的背包容积是从小到大,所以我们取最大的 min(n,m)min(n, m) 个背包就好。然后我们第一维枚举每一块奶酪,对这么些个背包而言取不取这块奶酪,这里就是 0101 背包,判断完之后,更新一下下一位背包,下一个背包如果不取当前奶酪的话,那么 dp[j+1][0]=max(dp[j+1][0],dp[j][k])dp[j + 1][0] = max(dp[j + 1][0], dp[j][k]), 就可以更新下一个背包不取当前奶酪的情况。最后对第 dp[m][i]dp[m][i] 寻找最大价值方案。

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
#include<bits/stdc++.h>
using namespace std;
const int N = 210;
int a[N], b[N], w[100010];
int dp[N][N];
int main(){
//ios::sync_with_stdio(0); cin.tie(0);
int n, m, mx = 0; cin >> n >> m;
for(int i = 1; i <= n; ++ i) cin >> a[i] >> b[i];
for(int i = 1; i <= m; ++ i) cin >> w[i];
if(m > n) {for(int i = 1; i <= n; ++ i) w[i] = w[i + m - n]; m = n;}
for(int i = 1; i <= n; ++ i){
for(int j = 1; j <= m; ++ j){
for(int k = w[j]; k >= a[i]; -- k){
dp[j][k] = max(dp[j][k], dp[j][k - a[i]] + b[i]);
}
}
for(int j = 1; j < m; ++ j){
for(int k = 0; k <= w[j]; ++ k){
dp[j + 1][0] = max(dp[j + 1][0], dp[j][k]);
}
}
}

for(auto &x: dp[m]) mx = max(mx, x);
cout << mx;
}
上一篇:
牛客暑期多校训练营7
下一篇:
牛客暑期多校训练营4