A:疫苗小孩
题意 | 简单
- 打疫苗一共可以打三针,且只有后两针接种才能提升手速,且一天最多只能打一针。后一针疫苗与前一针疫苗之间相隔k天对手速的提升最为明显,每偏离一天则效果会想应减少,每偏离一天则效果减少q的话,则后一针疫苗实际对人手速的影响为w - |k - p| * q
- n天以后就是比赛,只考虑n天内疫苗的接种,但这n天中只能挑没有牛客比赛的日子去打疫苗
n n n ≤ \leq ≤ 1 0 6 10^6 106 , 1 ≤ \leq ≤ k , w , q k,w,q k,w,q ≤ \leq ≤ 1 0 9 10^9 109
思路 | 贪心
- 枚举第二针所在的位置pos ,二分找到离pos+k和pos-k最近的两个点计算最大贡献就可以啦
代码
#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int maxn = 1e6 + 100;
int a[maxn];
void solve() {
int n; string s; cin >> n >> s;
s = '.' + s;
int k, w, q;cin >> k >> w >> q;
int cnt = 0;
a[cnt] = n + 1;
for (int i = 1; i <= n; i++) if (s[i] == '0')a[++cnt] = i;
a[cnt + 1] = n + 1;
int maxx = 0;
for (int i = 1; i <= cnt; i++) {
int posb = a[i];
int posa1 = a[lower_bound(a + 1, a + 1 + cnt, posb - k) - a - 1];
int posa2 = a[lower_bound(a + 1, a + 1 + cnt, posb - k) - a];
int posc1 = a[lower_bound(a + 1, a + 1 + cnt, posb + k) - a - 1];
int posc2 = a[lower_bound(a + 1, a + 1 + cnt, posb + k) - a];
if (posa1 < posb && posb <= a[cnt]) maxx = max(maxx, w - abs(posb + k - posa1) * q);
if (posa2 < posb && posb <= a[cnt]) maxx = max(maxx, w - abs(posb + k - posa2) * q);
if (posa1 < posb && posb < posc1 && posc1 <= a[cnt]) maxx = max(maxx, 2 * w - abs(posa1 + k - posb) * q - abs(posb + k - posc1) * q);
if (posa1 < posb && posb < posc2 && posc2 <= a[cnt]) maxx = max(maxx, 2 * w - abs(posa1 + k - posb) * q - abs(posb + k - posc2) * q);
if (posa2 < posb && posb < posc1 && posc1 <= a[cnt]) maxx = max(maxx, 2 * w - abs(posa2 + k - posb) * q - abs(posb + k - posc1) * q);
if (posa2 < posb && posb < posc2 && posc2 <= a[cnt]) maxx = max(maxx, 2 * w - abs(posa2 + k - posb) * q - abs(posb + k - posc2) * q);
}
cout << maxx << endl;
}
signed main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int t; t = 1;
while (t--) {
solve();
}
return 0;
}
C:战棋小孩
题意 | 简单
- 进行
n
n
n局游戏,每局游戏可以从两个英雄种选择一位,同时如果选择礼遇的话就会拥有再多两个英雄的选择。现在给出每局游戏的选将情况和结束后上榜需要的分数,和每局游戏结束后,排行榜上需要的分数,现在想直到通过能力合理排列并进行最优选择后,他最多因上榜而开心的次数。
n , k , s n,k,s n,k,s分别表示游戏局数,可使用礼遇的次数和初试分数
0 ≤ \leq ≤ n , k n,k n,k ≤ \leq ≤ 20 20 20
思路 | 枚举
- 二进制枚举一下哪些位置需要使用礼遇,然后再排序一下(从大到小)就可以了(证明),按照累加是判断否可以得分
代码
#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int maxn = 1e6 + 100;
const int mod = 1e9 + 7;
struct node {
int val, maxval;
}a[maxn];
int p[maxn];
int b[maxn];
bool cmp(int a, int b) {
return a > b;
}
void solve() {
int n, k, s;
cin >> n >> k >> s;
int maxx = 0;
for (int i = 0; i < n; i++) cin >> p[i];
for (int i = 0; i < n; i++) {
int aa, bb, c, d;
cin >> aa >> bb >> c >> d;
a[i].val = max(aa, bb);
a[i].maxval = max(a[i].val, max(c, d));
}
for (int i = 0; i < (1 << n); i++) {
int cnt = 0;
for (int j = 0; j < n; j++) {
if (i & (1 << j)) b[j] = a[j].maxval, cnt++;
else b[j] = a[j].val;
}
if (cnt <= k) {
sort(b, b + n, cmp);
int sum = s;
int ans = 0;
for (int j = 0; j < n; j++) {
sum += b[j];
if (sum >= p[j]) ans++;
}
maxx = max(maxx, ans);
}
}
cout << maxx << endl;
}
signed main() {
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int t; t = 1;
while (t--) {
solve();
}
return 0;
}
D:数位小孩
题意 | 简单
-
给定一个区间 [ l , r l,r l,r] ,求这个区间内有多少个数字满足以下条件:
- 每相邻两个数位和为素数
- 其中至少一个数位为1
- 没有前导零
-
0 ≤ \leq ≤ l , r l,r l,r ≤ \leq ≤ 1 0 10 10^{10} 1010
思路 | 暴力
- 因为数据范围不大,可以直接写一个dfs进行暴力寻找,把哪些数字可以相邻在一起的先预处理出来,然后就暴力开找就行啦
代码
#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
const int maxn = 1e6 + 100;
typedef long long ll;
ll prime[1006];
bool sf[2006];
void sushu() {
ll num = 0;
memset(sf, true, sizeof(sf));
sf[1] = false;
sf[0] = false;
for (int i = 2; i < 1000; i++) {
if (sf[i]) prime[++num] = i;
for (int j = 1; j <= num; j++) {
if (i * prime[j] > 1000) break;
sf[i * prime[j]] = false;
if (i % prime[j] == 0) break;
}
}
}
int l, r;
int ans1 = 0; int ans2 = 0;
vector<int>g[100];
void dfs(int x,int sum,int f) {
if (sum < l) {
if (f == 1) ans1++;
}
else return;
for (int i = 0; i < g[x].size(); i++) {
int to = g[x][i];
if (to == 1) dfs(to, sum * 10 + to, 1);
else dfs(to, sum * 10 + to, f);
}
}
void dfs2(int x, int sum,int f) {
if (sum <= r) {
if (f == 1) ans2++;
}
else return;
for (int i = 0; i < g[x].size(); i++) {
int to = g[x][i];
if (to == 1) dfs2(to, sum * 10 + to, 1);
else dfs2(to, sum * 10 + to, f);
}
}
void solve() {
for (int i = 0; i <= 9; i++) {
for (int j = 0; j <= 9; j++) {
if (sf[i + j])g[i].push_back(j);
}
}
cin >> l >> r;
for (int i = 1; i <= 9; i++) {
if (i == 1) {
dfs(i, i, 1);
dfs2(i, i, 1);
}
else {
dfs(i, i, 0);
dfs2(i, i, 0);
}
}
cout << ans2 - ans1 << endl;
}
signed main() {
int t; t = 1;
sushu();
while (t--) {
solve();
}
return 0;
}
E:复苏小孩
题意 | 简单
-
给一串长度为 n n n的字符串,字符串里面的字符仅包含 ‘1’,‘2’,‘3’,分别表示使用鬼眼,鬼影,鬼手的能力。每使用其中一个鬼的能力,这个鬼就会吸收其他两个鬼各一半的能力,且假设这三种鬼的能力值为1,按照这个字符串顺序使用对应鬼的能力后,将三种鬼的力量值%998244353代入
-
有 m m m次操作,每行三个整数
1 x y : 表示修改字符串的第x位修改成数字y
2 x y : 表示查询 l,r 这段字符串 -
0 ≤ \leq ≤ n , m n,m n,m ≤ \leq ≤ 1 0 5 10^{5} 105