目录
A - First ABC 2
tag:签到
题解:
从第一个位置遍历到n-2个位置即可,每次遍历判断这三个字符是否依次为ABC
// 加油昂!!!
// Problem: A - First ABC 2
// Contest: AtCoder - AtCoder Beginner Contest 322
// URL: https://atcoder.jp/contests/abc322/tasks/abc322_a
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef double db;
const int N = 1e5+5, M = 1e9+7;
#define YES {cout<<"YES"<<endl;return ;}
#define NO {cout<<"NO"<<endl;return ;}
void solve()
{
int n;
cin>>n;
string s;
cin>>s;
for(int i=0;i<n-2;i++)
{
if(s[i] == 'A' && s[i+1] == 'B' && s[i+2] == 'C')
{
cout<<i+1<<"\n";
return ;
}
}
cout<<"-1\n";
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--)
solve();
return 0;
}
B - Prefix and Suffix
tag:签到,模拟
题解:
根据题目用两个数字分别存储是否为前缀和后缀,如果是前缀,对应的数字为0,否则对应的数字为2;如果是后缀,对应的数字为0,否则对应的数字为1。最终答案直接输出两数字之和即可。
// 加油昂!!!
// Problem: B - Prefix and Suffix
// Contest: AtCoder - AtCoder Beginner Contest 322
// URL: https://atcoder.jp/contests/abc322/tasks/abc322_b
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef double db;
const int N = 1e5 + 5, M = 1e9 + 7;
void solve()
{
int n, m;
cin >> n >> m;
string s, t;
cin >> s >> t;
int ans_q = 0, ans_h = 0;
for (int i = 0, j = 0; i < n; i++, j++)
{
if(s[i] != t[j])
{
ans_q = 2;
break;
}
}
for (int i = n - 1, j = m - 1; i >= 0; i--, j--)
{
if (s[i] != t[j])
{
ans_h = 1;
break;
}
}
cout << ans_q + ans_h << "\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
//cin >> t;
while (t--)
solve();
return 0;
}
C - Festival
tag:二分
题解:
翻译一下题意就变成了找到数组中第一个大于等于()的数字,并用其减去。数组具有单调性,直接在循环里面用二分即可。
另外:这个题需要每个数字都找到一个大于等于的数组位置,所以还可以用一个数字存储当前到达的数组位置,如果小于了遍历到的数字,就往后面移动一个位置,然后得到答案。(这个方法比二分方法速度还快一点)。
二分代码:
// 加油昂!!!
// Problem: C - Festival
// Contest: AtCoder - AtCoder Beginner Contest 322
// URL: https://atcoder.jp/contests/abc322/tasks/abc322_c
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef double db;
const int N = 1e5+5, M = 1e9+7;
#define YES {cout<<"YES"<<endl;return ;}
#define NO {cout<<"NO"<<endl;return ;}
void solve()
{
int n, m;
cin >> n >> m;
vector<int> a(m);
for (int i = 0; i < m; i++)
{
cin >> a[i];
}
auto check = [&](int x) -> int{
int l = 0, r = m-1;
while(l < r)
{
int mid = (l + r) >> 1;
if (a[mid] < x) l = mid + 1;
else r = mid;
}
return r;
};
for (int i = 1; i <= n; i++)
{
cout << a[check(i)] - i << "\n";
}
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--)
solve();
return 0;
}
普通做法:
// 加油昂!!!
// Problem: C - Festival
// Contest: AtCoder - AtCoder Beginner Contest 322
// URL: https://atcoder.jp/contests/abc322/tasks/abc322_c
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef double db;
const int N = 1e5+5, M = 1e9+7;
#define YES {cout<<"YES"<<endl;return ;}
#define NO {cout<<"NO"<<endl;return ;}
void solve()
{
int n, m;
cin >> n >> m;
vector<int> a(m);
for (int i = 0; i < m; i++)
{
cin >> a[i];
}
int last = 0;
for (int i = 1; i <= n; i++)
{
if (a[last] < i) last++;
cout << a[last] - i << "\n";
}
}
signed main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--)
solve();
return 0;
}
D - Polyomino
tag:暴力,模拟
题解:
这个题看完数据范围就知道是暴力模拟了,直接枚举每一个图案的所有可能的位置和旋转的角度,然后三个图案再分别取出来一种进行判断是否能合成一整个方块。(我的旋转是直接swap,也可以使用题解的)
// 加油昂!!!
// Problem: D - Polyomino
// Contest: AtCoder - AtCoder Beginner Contest 322
// URL: https://atcoder.jp/contests/abc322/tasks/abc322_d
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef double db;
const int N = 1e5 + 5, M = 1e9 + 7;
auto check = [](vector<char> c, int x1, int x2, int x3, int x4) -> bool {
if (c[x1] != '.' || c[x2] != '.' || c[x3] != '.' || c[x4] != '.')
return false;
return true;
}; //如果四个点都是.,我们才向这个方向进行移动操作
auto move_l = [](vector<char> c, vector<vector<char>> &ans) -> void {
while (check(c, 0, 4, 8, 12))
{
for (int i = 0; i < 15; i += 4)
{
for (int j = i; j < i + 3; j++)
{
swap(c[j], c[j + 1]);
}
}
ans.push_back(c);
}
}; //左移动
auto move_r = [](vector<char> c, vector<vector<char>> &ans) -> void {
while (check(c, 3, 7, 11, 15))
{
for (int i = 0; i < 15; i += 4)
{
for (int j = i + 3; j > i; j--)
{
swap(c[j], c[j - 1]);
}
}
ans.push_back(c);
}
}; //右移动
bool find(vector<char> a, vector<char> b, vector<char> c)
{
for (int i = 0; i < 16; i++)
{
if (a[i] + b[i] + c[i] != '.' + '.' + '#')
return false;
}
return true;
} //判断是否有重叠和为填满的情况
void solve()
{
auto xuan = [](vector<char> &c) -> void {
swap(c[0], c[12]);
swap(c[0], c[15]);
swap(c[0], c[3]);
swap(c[1], c[8]);
swap(c[1], c[14]);
swap(c[1], c[7]);
swap(c[4], c[13]);
swap(c[4], c[11]);
swap(c[4], c[2]);
swap(c[5], c[9]);
swap(c[5], c[10]);
swap(c[5], c[6]);
}; //进行旋转操作
auto move_s = [](vector<char> c, vector<vector<char>> &ans) -> void {
while (check(c, 0, 1, 2, 3))
{
for (int i = 0; i < 4; i++)
{
for (int j = i; j < 12; j += 4)
{
swap(c[j], c[j + 4]);
}
}
ans.push_back(c);
move_l(c, ans);
move_r(c, ans);
}
}; //上移动
auto move_x = [](vector<char> c, vector<vector<char>> &ans) -> void {
while (check(c, 12, 13, 14, 15))
{
for (int i = 12; i < 16; i++)
{
for (int j = i; j > 3; j -= 4)
{
swap(c[j], c[j - 4]);
}
}
ans.push_back(c);
move_l(c, ans);
move_r(c, ans);
}
}; //下移动
vector<vector<char>> ans[3]; //存储三个图案的全部可能
for (int i = 0; i < 3; i++)
{
vector<char> c(16);
for (int j = 0; j < 16; j++)
{
cin >> c[j];
}
for (int k = 0; k < 4; k++)
{
if (k)
xuan(c);
ans[i].push_back(c);
move_s(c, ans[i]);
move_x(c, ans[i]);
move_l(c, ans[i]);
move_r(c, ans[i]);
}
}
for (int i = 0; i < ans[0].size(); i++)
{
for (int j = 0; j < ans[1].size(); j++)
{
for (int k = 0; k < ans[2].size(); k++)
{
if (find(ans[0][i], ans[1][j], ans[2][k]))
{
cout << "Yes\n";
return;
}
}
}
}
cout << "No\n";
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
// cin>>t;
while (t--)
solve();
return 0;
}
E - Product Development
tag:背包
题解:
很容易能看出是一个背包问题,只不过是将一维背包变成了多维背包,背包最大维度为5,对于每一个维度有一个最大值p或者0,前k维度最大值为p,其余的都为0,然后就是简单的背包DP模型,还要注意这个地方的dp数组的初始值应该设置为1e11以上,不然就会wa几个点。
// 加油昂!!!
// Problem: E - Product Development
// Contest: AtCoder - AtCoder Beginner Contest 322
// URL: https://atcoder.jp/contests/abc322/tasks/abc322_e
// Memory Limit: 1024 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e17;
int dp[6][6][6][6][6];
void solve()
{
for (int x0 = 5; x0 >= 0; x0--)
{
for (int x1 = 5; x1 >= 0; x1--)
{
for (int x2 = 5; x2 >= 0; x2--)
{
for (int x3 = 5; x3 >= 0; x3--)
{
for (int x4 = 5; x4 >= 0; x4--)
{
dp[x0][x1][x2][x3][x4] = N;
}
}
}
}
}
dp[0][0][0][0][0] = 0;
int n, k, p;
cin >> n >> k >> p;
vector<int> h(5);
for (int i = 0; i < k; i++)
h[i] = p;
for (int i = 0; i < n; i++)
{
int v;
cin >> v;
vector<int> w(5);
for (int j = 0; j < k; j++)
{
cin >> w[j];
}
for (int x0 = h[0]; x0 >= 0; x0--)
{
for (int x1 = h[1]; x1 >= 0; x1--)
{
for (int x2 = h[2]; x2 >= 0; x2--)
{
for (int x3 = h[3]; x3 >= 0; x3--)
{
for (int x4 = h[4]; x4 >= 0; x4--)
{
if (dp[x0][x1][x2][x3][x4] == INT_MAX) continue;
int xx0 = min(h[0], x0 + w[0]), xx1 = min(h[1], x1 + w[1]), xx2 = min(h[2], x2 + w[2]),
xx3 = min(h[3], x3 + w[3]), xx4 = min(h[4], x4 + w[4]);
dp[xx0][xx1][xx2][xx3][xx4] = min(dp[xx0][xx1][xx2][xx3][xx4], dp[x0][x1][x2][x3][x4] + v);
}
}
}
}
}
}
int ans = dp[h[0]][h[1]][h[2]][h[3]][h[4]];
cout << (ans == N ? -1 : ans);
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
//cin>>t;
while(t--)
solve();
return 0;
}
F - Vacation Query
tag:线段树
本题的加强版:P2572 [SCOI2010] 序列操作 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题解:
本题能很显然的看出是线段树来进行区间修改操作,懒标记标记修改区间,套线段树的板子,但是我们该如何维护每段的最长子段1呢,第一种,将整个区间取反,那么最长子段0就变成了最长子段1,因此需要保存最长子段0这个量;第二种,两个区间合并的最大值该怎么计算,首先是左右区间的最大值比较,还有一种可能就是两个区间的断面连起来大于两个区间的最大值也会计入答案,所以是三个值取最大,所以需要记录从左边和右边起的1/0串的长度;假设左边的区间全是1,那么合并区间的左起的1串的长度就应该再加上右边的区间的左起的1串长度,因为取反操作存在的原因,所以需要把0的相关信息也保存。(如代码中注释)
// 加油昂!!!
// Problem: F - Vacation Query
// Contest: AtCoder - AtCoder Beginner Contest 322
// URL: https://atcoder.jp/contests/abc322/tasks/abc322_f
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 5, M = 1e9 + 7;
char c[5 * N];
struct tree
{
int l, r;
int l0 = 0, l1 = 0, r0 = 0, r1 = 0, max1 = 0, max0 = 0, s0 = 0, s1 = 0;
/*左起1/0最长长度,右起1/0最长长度
区间0/1最长长度,区间0/1总和
区间左端点,区间右端点*/
int lazy = 0;
} tr[20 * N];
void did(int p)
{
swap(tr[p].l0, tr[p].l1);
swap(tr[p].r1, tr[p].r0);
swap(tr[p].max1, tr[p].max0);
swap(tr[p].s0, tr[p].s1);
(tr[p].lazy += 1) %= 2;
}
void pushdown(int p)
{
if (!tr[p].lazy) return;
did(p << 1);
did(p << 1 | 1);
tr[p].lazy = 0;
}
void pushup(tree &p, tree p1, tree p2)
{
p.s0 = p1.s0 + p2.s0;
p.s1 = p1.s1 + p2.s1;
p.l1 = p1.s0 == 0 ? p1.l1 + p2.l1 : p1.l1;
p.l0 = p1.s1 == 0 ? p1.l0 + p2.l0 : p1.l0;
p.r1 = p2.s0 == 0 ? p2.r1 + p1.r1 : p2.r1;
p.r0 = p2.s1 == 0 ? p2.r0 + p1.r0 : p2.r0;
p.max1 = max(max(p1.max1, p2.max1), p1.r1 + p2.l1);
p.max0 = max(max(p1.max0, p2.max0), p1.r0 + p2.l0);
}
void bulid(int p, int l, int r)
{
if (l == r)
{
tr[p].l = tr[p].r = l;
if (c[l] == '1')
{
tr[p].l1 = tr[p].r1 = tr[p].s1 = tr[p].max1 = 1;
}
else
{
tr[p].l0 = tr[p].r0 = tr[p].s0 = tr[p].max0 = 1;
}
return;
}
bulid(p << 1, l, (l + r) / 2);
bulid(p << 1 | 1, (l + r) / 2 + 1, r);
tr[p].l = l, tr[p].r = r;
pushup(tr[p],tr[p << 1],tr[p << 1 | 1]);
}
tree getmax(int p, int l, int r)
{
if (tr[p].l >= l && tr[p].r <= r)
{
return tr[p];
}
pushdown(p);
tree ans, p1, p2;
int mid = (tr[p].l + tr[p].r) >> 1;
if (l <= mid) p1 = getmax(p * 2, l, r);
if (r > mid) p2 = getmax(p * 2 + 1, l, r);
pushup(ans, p1, p2);
return ans;
}
void update(int p, int l, int r)
{
if (tr[p].l >= l && tr[p].r <= r)
{
did(p);
return;
}
pushdown(p);
int mid = (tr[p].l + tr[p].r) >> 1;
if (l <= mid) update(p << 1, l, r);
if (r > mid) update(p << 1 | 1, l, r);
pushup(tr[p], tr[p << 1], tr[p << 1 | 1]);
}
void solve()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> c[i];
}
bulid(1, 1, n);
while (m--)
{
int p, l, r;
cin >> p;
if (p == 1)
{
cin >> l >> r;
update(1, l, r);
}
else
{
cin >> l >> r;
cout << getmax(1, l, r).max1 << "\n";
}
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t = 1;
// cin >> t;
while (t--)
solve();
return 0;
}