A.Tomorrow(模拟)
题意:
有一本日历,一年有MMM个月,一个月有DDD天,现在给你一个日期,给出的形式是XXXXXX年,XXXXXX月,XXXXXX日。问这个日期后面一天是哪一天。
分析:
按照要求模拟即可。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
int t = 1;
while (t--) {
int M, D;
cin >> M >> D;
int y, m, d;
cin >> y >> m >> d;
d++;
if (d > D)
d = 1, m++;
if (m > M)
m = 1, y++;
cout << y << ' ' << m << ' ' << d << endl;
}
return 0;
}
B.Buy One Carton of Milk(枚举)
题意:
666个鸡蛋SSS元,888个鸡蛋MMM元,121212个鸡蛋LLL元,问至少买NNN个鸡蛋需要多少钱。
分析:
分别枚举买666个,888个,121212个一包的鸡蛋的数量,取最小值即可。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
int n, s, m, l;
cin >> n >> s >> m >> l;
int ans = 1e9;
for (int a = 0; a <= n; a++) {
for (int b = 0; b <= n; b++) {
for (int c = 0; c <= n; c++) {
if (a * 6 + b * 8 + c * 12 >= n) {
ans = min(ans, a * s + b * m + c * l);
}
}
}
}
cout << ans << endl;
return 0;
}
C.Sum of Numbers Greater Than Me(后缀和)
题意:
给出一个aaa序列,对于aia_iai,问大于aia_iai的所有元素之和是多少。
分析:
因为ai≤106a_i\le10^6ai≤106,我们从大到小枚举iii,sum[i]sum[i]sum[i]表示大于等于aia_iai的数字之和。先将aia_iai出现次数记录到sum[ai]sum[a_i]sum[ai]中。从大到小递推可得sum[i]=sum[i+1]+i∗sum[i]sum[i]=sum[i+1]+i*sum[i]sum[i]=sum[i+1]+i∗sum[i]
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10;
LL sum[N], a[N];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
sum[a[i]]++;
}
for (int i = 1000000; i >= 1; i--)
sum[i] = sum[i + 1] + sum[i] * i;
for (int i = 0; i < n; i++)
cout << sum[a[i] + 1] << ' ';
return 0;
}
D Tile Pattern(二维前缀和)
题意:
给一张109∗10910^9*10^9109∗109的网格图,P[i][j]P[i][j]P[i][j]表示第iii行,第jjj列格子的颜色,网格图剩下格子的颜色为P[i%n][j%n]P[i\%n][j\%n]P[i%n][j%n]。询问给出矩形左上角的坐标(A,B)(A,B)(A,B),右下角的坐标(C,D)(C,D)(C,D),输出矩形内黑格子的数量。
分析:
先预处理 n∗nn∗nn∗n 的范围内的二维前缀和。记以 (0,0)(0,0)(0,0) 为左上角, (x,y)(x,y)(x,y) 为右下角的黑格子的数量为 f(x,y)f(x,y)f(x,y)
对于一整个区域,我们分为四部分:
- 左上角的 (x/n)∗(y/n)(x/n)∗(y/n)(x/n)∗(y/n) 个 n∗nn∗nn∗n 的范围
- 右上角的 (x/n)(x/n)(x/n) 个 n∗(y%n)n∗(y\%n)n∗(y%n) 的范围
- 左下角的 (y/n)(y/n)(y/n) 个 n∗(x%n)n∗(x\%n)n∗(x%n) 的范围
- 右下角的 1 个 (x%n)∗(y%n)(x\%n)∗(y\%n)(x%n)∗(y%n)的范围
由二维前缀和以及容斥原理可知:ans=f(c,d)−f(c,b−1)−f(a−1,d)+f(a−1,b−1)ans=f(c,d)−f(c,b−1)−f(a−1,d)+f(a−1,b−1)ans=f(c,d)−f(c,b−1)−f(a−1,d)+f(a−1,b−1)
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e3 + 10;
char mp1[N][N];
int sum[N][N];
int n, q;
LL cal(int x, int y) {
LL res = 0;
res += 1ll * (x / n) * (y / n) * sum[n][n];
res += 1ll * (y / n) * sum[x % n][n];
res += 1ll * (x / n) * sum[n][y % n];
res += 1ll * sum[x % n][y % n];
return res;
}
int main() {
cin >> n >> q;
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
cin >> mp1[i][j];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
sum[i][j] = (mp1[i - 1][j - 1] == 'B') + sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
}
}
while (q--) {
int a, b, c, d;
cin >> a >> b >> c >> d;
cout << cal(c + 1, d + 1) - cal(c + 1, b) - cal(a, d + 1) + cal(a, b) << endl;
}
return 0;
}
E Set Meal(数据结构)
题意:
nnn道主菜,mmm道副菜,现在要选择一种主菜一种副菜作为一种组合菜。有LLL种主菜+副菜的组合菜是不提供的。询问剩下的组合菜价值之和最高的是多少。
分析:
将aaa,bbb数组从小到大排序之后,把它们的组合看成一个n∗mn*mn∗m 的矩阵,那么我们每次只需要取右下角这个最大的值出来,先判断可不可以选,如果可以选, 那它就是答案,否则继续将这个值左边的值和上边的值放进大根堆里继续重复即可。注意判断每个数有没有被拿过,拿过的数不要重复拿。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define PII pair<int, int>
#define x first
#define y second
int main() {
int n, m, l;
cin >> n >> m >> l;
vector<PII> a(n), b(m);
for (int i = 0; i < n; i++) {
cin >> a[i].x;
a[i].y = i;
}
for (int i = 0; i < m; i++) {
cin >> b[i].x;
b[i].y = i;
}
sort(a.begin(), a.end());
sort(b.begin(), b.end());
set<PII> ban;
while (l--) {
int c, d;
cin >> c >> d;
ban.insert({c - 1, d - 1});
}
priority_queue<tuple<int, int, int>> q;
set<PII> vis;
q.push({a[n - 1].x + b[m - 1].x, n - 1, m - 1});
vis.insert({n - 1, m - 1});
while (!q.empty()) {
auto [v, i, j] = q.top();
q.pop();
if (!ban.count({a[i].y, b[j].y})) {
cout << v << '\n';
return 0;
}
if (i - 1 >= 0 && !vis.count({i - 1, j})) {
q.push({a[i - 1].x + b[j].x, i - 1, j});
vis.insert({i - 1, j});
}
if (j - 1 >= 0 && !vis.count({i, j - 1})) {
q.push({a[i].x + b[j - 1].x, i, j - 1});
vis.insert({i, j - 1});
}
}
return 0;
}
F Palindrome Query(数据结构+哈希)
题意:
给出一个长度为nnn的字符串sss,第一种操作:修改s[x]=cs[x]=cs[x]=c,第二种操作:判断s[l,r]s[l,r]s[l,r]是不是回文串。
分析:
用树状数组维护字符串的正序哈希值和逆序哈希值,修改操作相当于在树状数组中先求出删去一个字母的哈希值,再计算加上这个字母的哈希值。判断回文操作只要求出[l,r][l,r][l,r]的正序哈希值和逆序哈希值,判断是否相等即可。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define lowbit(x) (x & (-x))
const int modd = 1e9 + 7;
LL n, q, pw[1000005], t1[1000005], t2[1000005];
string s;
LL binpow(LL a, LL b, LL m) {
a %= m;
LL res = 1;
while (b > 0) {
if (b & 1)
res = res * a % m;
a = a * a % m;
b >>= 1;
}
return res;
}
void ins(LL x, char e) { //插入
for (int i = x; i <= n; i += lowbit(i))
t1[i] = (t1[i] + (e - 'a') * pw[x - 1] % modd) % modd;
for (int i = x; i <= n; i += lowbit(i))
t2[i] = (t2[i] + (e - 'a') * pw[n - x] % modd) % modd;
}
void upd(LL x, char e) {//更新
for (int i = x; i <= n; i += lowbit(i))
t1[i] = (t1[i] - (s[x] - 'a') * pw[x - 1] % modd + modd) % modd;
for (int i = x; i <= n; i += lowbit(i))
t2[i] = (t2[i] - (s[x] - 'a') * pw[n - x] % modd + modd) % modd;
for (int i = x; i <= n; i += lowbit(i))
t1[i] = (t1[i] + (e - 'a') * pw[x - 1] % modd) % modd;
for (int i = x; i <= n; i += lowbit(i))
t2[i] = (t2[i] + (e - 'a') * pw[n - x] % modd) % modd;
s[x] = e;
}
LL qry(LL l, LL r) {//查询
LL res1 = 0, res2 = 0, L = (l + r + 1) / 2, R = r;
for (int i = R; i >= 1; i -= lowbit(i))
res1 = (res1 + t1[i]) % modd;
for (int i = L - 1; i >= 1; i -= lowbit(i))
res1 = (res1 - t1[i] + modd) % modd;
res1 = res1 * binpow(pw[L - 1], modd - 2, modd) % modd;
L = l, R = (l + r) / 2;
for (int i = R; i >= 1; i -= lowbit(i))
res2 = (res2 + t2[i]) % modd;
for (int i = L - 1; i >= 1; i -= lowbit(i))
res2 = (res2 - t2[i] + modd) % modd;
res2 = res2 * binpow(pw[n - R], modd - 2, modd) % modd;
return res1 == res2;
}
void solve() {
cin >> n >> q;
cin >> s;
s = ' ' + s;
pw[0] = 1;
for (int i = 1; i <= n; ++i)
pw[i] = pw[i - 1] * 1331 % modd;
for (int i = 1; i <= n; ++i)
ins(i, s[i]);
while (q--) {
int op;
cin >> op;
if (op == 1) {
LL x;
cin >> x;
char e;
cin >> e;
upd(x, e);
} else {
int l, r;
cin >> l >> r;
if (qry(l, r))
cout << "Yes" << endl;
else
cout << "No" << endl;
}
}
}
int main() {
int t;
t = 1;
while (t--) {
solve();
}
return 0;
}
学习交流
以下为学习交流QQ群,群号: 546235402,每周题解完成后都会转发到群中,大家可以加群一起交流做题思路,分享做题技巧,欢迎大家的加入。

1496

被折叠的 条评论
为什么被折叠?



