2023牛客多校第五场 - D G H
比赛地址:传送门
赛时过了 3 题,后期坐大牢!
G 尺取法双指针
H 动态规划,背包DP
D Cirno's Perfect Equation Class
题意
给定 \(k, c, n\),求正数对 \((a,b)\) 的个数满足 $ka + b = c, b | c (c = bx, x \ge 1), gcd(a,b) \ge n $
思路
不难发现 b 是 c 的因子,所以枚举 b,判断相应的 a 是否满足条件即可
代码
void solve(){
int k, c, n;
cin >> k >> c >> n;
vector<int> s;
for(int i = 1; i * i <= c; ++ i){
if(c % i == 0){
s.push_back(i);
if(i * i != c) s.push_back(c / i);
}
}
sort(s.begin(), s.end());
int ans = 0;
for(auto b : s){
int a = (c - b) / k;
if(a * k == c - b && a > 0 && __gcd(a, b) >= n) ++ ans;
}
cout << ans << '\n';
return ;
}
G Go to Play Maimai DX
题意
给定长为 n 的数组和数 k ,数组中每个数均$\in [1, 4] $,需要找到最小的区间,包含至少一个数字 1,2,3,包含 k 个 4。
思路
尺取法即可
代码
//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long
using namespace std;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*
*/
const int maxm = 1e5 + 5, inf = 0x3f3f3f3f, mod = 998244353;
int n, k, a[maxm], c[5];
void solve(){
cin >> n >> k;
for(int i = 0; i < n; ++ i){
cin >> a[i];
}
int l = 0, r = 0, lei = 0, ans = n + 1;
while(r < n){
while(lei <= 4 && r < n){
++ c[a[r]];
if(c[a[r]] == 1) ++ lei;
++ r;
if(c[4] >= k && lei == 4) break;
}
-- r;
if(lei < 4 || c[4] < k) break;
while(c[a[l]] > 1 && a[l] != 4 || c[a[l]] > k && a[l] == 4){
-- c[a[l]];
++ l;
}
ans = min(ans, r - l + 1);
-- c[a[l]];
if(c[a[l]] == 0) -- lei;
++ l;
++ r;
}
cout << ans << '\n';
return ;
}
signed main(){
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
// cin >> _;
while(_ --){
solve();
}
return 0;
}
H Nazrin the Greeeeeedy Mouse
题意
详见题面
There're $ n $ cheeses in the house. The $i-th $ cheese is between point $i $ and point $i + 1 $ . The \(i-th\) cheese's size is \(a_i\) and its weight is $b_i $.
Nazrin is at point $1 $ in the beginning and wants to steal some cheeses. She has $m $ chances to take the cheeses:
In the $i-th $ time, Nazrin brings a bag of size \(sz_i\) . Since she's greedy, for \(i > 1\),$sz_i > sz_{i - 1} $ always holds. She can travel from point \(1\) and take some cheeses. She can only travel from point \(x\) to \(x + 1\), or backwards. If she wants to travel from point \(x\) to point \(x + 1\), she has to dig a hole on the \(x-th\) cheese or take it. She can't take a cheese with a hole on it. Of course, the sum of the cheeses' size she takes in the \(i-th\) time can't be larger than \(sz_i\). After taking the cheeses, she needs to go back to point 1.
Please maximize the sum of the weights of taken cheeses and output it.
$1 \le n \le 200, 1 \le m \le 10^5, 1 \le a_i \le 200, 1 \le b_i \le 10^5, 1\le sz_i \le 200 $
思路
没那么简单的01背包DP,多个01相互牵制背包DP取最优
有个小提示就是当 \(n < m\) 时,我们可以仅用后 n 个背包即可。从前往后遍历物品,对于每一个背包都做背包DP,那么我们就可以获得对于所有背包自己的最大值,之后我们再进行一步操作,就是将前一个背包的最大值转移到后一个背包的 0 空间上去,因为最终的最大如果不在单个背包上取,那就在多个背包共同取,而后一个背包取需要在前一个背包的基础上取!
理解的还不是很透彻,详见代码。。。
代码
//>>>Qiansui
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define mem(x,y) memset(x, y, sizeof(x))
#define debug(x) cout << #x << " = " << x << '\n'
#define debug2(x,y) cout << #x << " = " << x << " " << #y << " = "<< y << '\n'
//#define int long long
using namespace std;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<ull, ull> pull;
typedef pair<double, double> pdd;
/*
*/
const int maxm = 2e2 + 5, inf = 0x3f3f3f3f, mod = 998244353;
void solve(){
int n, m;
cin >> n >> m;
vector<int> a(n), b(n), h(m);
for(int i = 0; i < n; ++ i){
cin >> a[i] >> b[i];
}
for(int c = 0; c < m; ++ c){
cin >> h[c];
}
if(m > n){
h.erase(h.begin(), h.end() - n);
m = n;
}
vector<vector<int>> dp(m, vector<int>(maxm, 0));
for(int i = 0; i < n; ++ i){ // i 个物品
for(int j = 0; j < m; ++ j){ //每个包
for(int k = h[j]; k >= a[i]; --k){
dp[j][k] = max(dp[j][k], dp[j][k - a[i]] + b[i]);
}
}
for(int j = 0; j < m - 1; ++ j){ //将前面的最优状态转到下一背包的 0 空间状态
for(int k = 0; k <= h[j]; ++ k){
dp[j + 1][0] = max(dp[j + 1][0], dp[j][k]);
}
}
}
int ans = 0;
for(int i = 0; i <= h[m - 1]; ++ i){ //最终的答案即为最后一背包的最大值
ans = max(ans, dp[m - 1][i]);
}
cout << ans << '\n';
return ;
}
signed main(){
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
// cin >> _;
while(_ --){
solve();
}
return 0;
}