A. Buy the String
题解:
循环一遍判断是否转换哪个更便宜即可
代码:
/*
* @Author : Nightmare
*/
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define PII pair<int,int>
#define ls 2 * rt
#define rs 2 * rt + 1
#define gcd(a,b) __gcd(a,b)
#define eps 1e-6
#define lowbit(x) (x&(-x))
#define N 100005
#define M 10005
#define mod 1000000007
#define inf 0x3f3f3f3f
void solve(){
int n, c0, c1, h; cin >> n >> c0 >> c1 >> h;
string ss; cin >> ss;
int ans = 0;
for(auto &ch : ss){
if(ch == '0'){
ans += min(c0, c1 + h);
}else{
ans += min(c1, c0 + h);
}
}
cout << ans << '\n';
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("D:\\in.txt", "r", stdin);
#endif
int T; cin >> T; while(T--) solve();
#ifndef ONLINE_JUDGE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
B. Sum of Medians
题解:
通过n求出中间的位置为(n + 1) / 2,贪心将每组的前(n + 1) / 2 - 1个数放在前面,后面对每一组补成n个即可。
代码:
/*
* @Author : Nightmare
*/
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define PII pair<int,int>
#define ls 2 * rt
#define rs 2 * rt + 1
#define gcd(a,b) __gcd(a,b)
#define eps 1e-6
#define lowbit(x) (x&(-x))
#define N 200005
#define M 10005
#define mod 1000000007
#define inf 0x3f3f3f3f
int a[N];
void solve(){
int n, k; scanf("%lld %lld", &n, &k);
for(int i = 1 ; i <= n * k ; i ++) scanf("%lld", &a[i]);
int ans = 0, pq = (n + 1) / 2 - 1;
if(n == 1){
for(int i = 1 ; i <= n * k ; i ++) ans += a[i];
cout << ans << '\n';
return ;
}
if(n == 2){
for(int i = 1 ; i <= n * k ; i += 2) ans += a[i];
cout << ans << '\n';
return ;
}
for(int i = k * pq + 1 ; i <= n * k ; i += n - pq) ans += a[i];
cout << ans << '\n';
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("D:\\in.txt", "r", stdin);
#endif
int T; cin >> T; while(T--) solve();
#ifndef ONLINE_JUDGE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
C2. Binary Table (Hard Version)
题解:
模拟
对于一个2 x 2 的区域,按照区域中间的1的个数进行划分。
如果区域中没有1,不处理。
如果有一个1,对任意一个0进行一次操作,可以形成两个1的形式。
如果有两个1,对其中一个1进行一次操作,可以形成三个1的形式。
如果有三个1,对0处理一次即可。
如果有四个1,对任意一个1处理后,变成只有一个1的形式。
容易发现,每种划分都可以通过0~4次处理后变为有三个1的形式,所以操作次数 <= 2 * 2,总操作次数 <= n * m
当边界为奇数时,先将边界的1~2个1转化为0后,在统一进行处理。
代码:
/*
* @Author : Nightmare
*/
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define PII pair<int,int>
#define ls 2 * rt
#define rs 2 * rt + 1
#define gcd(a,b) __gcd(a,b)
#define eps 1e-6
#define lowbit(x) (x&(-x))
#define N 105
#define M 10005
#define mod 1000000007
#define inf 0x3f3f3f3f
char str[N][N]; int a[N][N];
vector<PII> v;
struct node{ int a, b; };
vector<node> res;
void change(int x, int y){
for(int i = 0 ; i < 4 ; i ++){
if(v[i].first == x && v[i].second == y) continue;
res.push_back({v[i].first, v[i].second});
a[v[i].first][v[i].second] ^= 1;
}
}
void solve(){
int n, m; scanf("%d %d", &n, &m);
res.clear();
for(int i = 1 ; i <= n ; i ++) scanf("%s", str[i] + 1);
for(int i = 1 ; i <= n ; i ++) for(int j = 1 ; j <= m ; j ++) a[i][j] = (str[i][j] - '0');
if((n & 1) && (m & 1) && a[n][m] == 1){ // 如果右下角为1,区域中任取一个非右下角的点操作即可。
v.clear();
v.emplace_back(n - 1, m - 1);
v.emplace_back(n - 1, m);
v.emplace_back(n, m - 1);
v.emplace_back(n, m);
change(n - 1, m - 1);
}
if(n & 1){ // 处理下边界
for(int i = 2 ; i <= m ; i += 2){
v.clear();
v.emplace_back(n, i - 1);
v.emplace_back(n, i);
v.emplace_back(n - 1, i - 1);
v.emplace_back(n - 1, i);
if(a[n][i - 1] + a[n][i] == 2){ // 两个值都为1,对两个格子都进行操作一次
change(n, i - 1);
change(n, i);
}else if(a[n][i - 1] + a[n][i] == 1){ // 对为0的格子操作一次
if(a[n][i - 1] == 0) change(n, i - 1);
else change(n, i);
}
}
}
if(m & 1){ // 处理右边界
for(int i = 2 ; i <= n ; i += 2){
v.clear();
v.emplace_back(i, m);
v.emplace_back(i - 1, m);
v.emplace_back(i, m - 1);
v.emplace_back(i - 1, m - 1);
if(a[i][m] + a[i - 1][m] == 2){ // 两个值都为1,对两个格子都进行操作一次
change(i, m);
change(i - 1, m);
}else if(a[i][m] + a[i - 1][m] == 1){ // 对为0的格子操作一次
if(a[i][m] == 0) change(i, m);
else change(i - 1, m);
}
}
}
for(int i = 2 ; i <= n ; i += 2){
for(int j = 2 ; j <= m ; j += 2){
v.clear();
v.emplace_back(i - 1, j - 1);
v.emplace_back(i - 1, j);
v.emplace_back(i, j - 1);
v.emplace_back(i, j);
if(a[i - 1][j - 1] + a[i - 1][j] + a[i][j - 1] + a[i][j] == 1){
for(int k = 0 ; k < 4 ; k ++){
if(a[v[k].first][v[k].second] == 1){
for(int p = 0 ; p < 4 ; p ++) // 对其他所有为0的格子都操作一次即可
if(p != k)
change(v[p].first, v[p].second);
break;
}
}
}else if(a[i - 1][j - 1] + a[i - 1][j] + a[i][j - 1] + a[i][j] == 2){
for(int p = 0, flag = 0; p < 4 && !flag ; p ++){
for(int q = p + 1 ; q < 4 ; q ++){
if(a[v[p].first][v[p].second] == 1 && a[v[q].first][v[q].second] == 1){
change(v[p].first, v[p].second); // 对两个为1的格子都操作一次
change(v[q].first, v[q].second);
flag = 1;
break;
}
}
}
}else if(a[i - 1][j - 1] + a[i - 1][j] + a[i][j - 1] + a[i][j] == 3){
for(int k = 0 ; k < 4 ; k ++){
if(a[v[k].first][v[k].second] == 0){
change(v[k].first, v[k].second); // 直接操作为0的格子即可
break;
}
}
}else if(a[i - 1][j - 1] + a[i - 1][j] + a[i][j - 1] + a[i][j] == 4){
change(i - 1, j - 1); // 对任意一个格子操作一次变为只有1个1的形式
change(i - 1, j);
change(i, j - 1);
change(i, j);
}
}
}
cout << res.size() / 3 << '\n';
for(int i = 0 ; i < res.size() ; i += 3){
cout << res[i].a << ' ' << res[i].b << ' ';
cout << res[i + 1].a << ' ' << res[i + 1].b << ' ';
cout << res[i + 2].a << ' ' << res[i + 2].b << '\n';
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("D:\\in.txt", "r", stdin);
#endif
int T; cin >> T; while(T--) solve();
#ifndef ONLINE_JUDGE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}
E. Greedy Shopping
题解:
操作1:1~x区间中所有小于y的数置为y
操作2:从x开始向右走,期间遇到的东西能买就买,问走到n总共能买多少件?
区间置max,考虑吉司机线段树,通过只修改区间min < val的区间进行剪枝,对于第二个操作,每次二分找到小于val的位置,再向右二分最多能连续买的位置,根据势能分析,每买一段区间,val的值一定下降至少一半,因此选取次数 < l o g ( v a l ) log(val) log(val)次,复杂度 O ( n l o g n 2 ) O(nlogn^2) O(nlogn2)
代码:
/*
* @Author : Nightmare
*/
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define ull unsigned long long
#define PII pair<int,int>
#define ls 2 * rt
#define rs 2 * rt + 1
#define gcd(a,b) __gcd(a,b)
#define eps 1e-6
#define lowbit(x) (x&(-x))
#define N 200005
#define M 10005
#define mod 1000000007
#define inf 0x3f3f3f3f
int n, Q, a[N];
struct SegmentBeat{
static const int maxn = 2e5 + 5;
struct node{ int l, r, mi, sum, tag; }t[maxn * 4];
void pushup(int rt){
t[rt].sum = t[ls].sum + t[rs].sum;
t[rt].mi = min(t[ls].mi, t[rs].mi);
}
void update(int rt, int v){
t[rt].mi = v;
t[rt].tag = max(t[rt].tag, v);
t[rt].sum = (t[rt].r - t[rt].l + 1) * v;
}
void pushdown(int rt){
if(t[rt].tag){
update(ls, t[rt].tag); update(rs, t[rt].tag);
t[rt].tag = 0;
}
}
void build(int rt, int l, int r){
t[rt].l = l; t[rt].r = r;
if(l == r){ t[rt].sum = t[rt].mi = a[l]; return ; }
int mid = (t[rt].l + t[rt].r) >> 1;
build(ls, l, mid); build(rs, mid + 1, r);
pushup(rt);
}
void change(int rt, int l, int r, int v){
if(l <= t[rt].l && t[rt].r <= r){
if(v > t[rt].mi) update(rt, v);
return ;
}
pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1;
if(l <= mid) change(ls, l, r, v);
if(r > mid) change(rs, l, r, v);
pushup(rt);
}
void set_max(int rt, int x, int y){
if(t[rt].l == t[rt].r){
if(t[rt].l <= x) change(1, t[rt].l, x, y);
return ;
}
pushdown(rt);
if(t[ls].mi <= y) set_max(ls, x, y);
else set_max(rs, x, y);
}
int query_sum(int rt, int l, int r){
if(l > r) return 0;
if(l <= t[rt].l && t[rt].r <= r) return t[rt].sum;
pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1, ans = 0;
if(l <= mid) ans += query_sum(ls, l, r);
if(r > mid) ans += query_sum(rs, l, r);
return ans;
}
int find(int rt, int val){
if(t[rt].l == t[rt].r){
if(t[rt].sum <= val) return t[rt].l;
else return t[rt].l - 1;
}
pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1;
if(t[ls].sum <= val) return find(rs, val - t[ls].sum);
else return find(ls, val);
}
int lower_bound(int rt, int val){
if(t[rt].l == t[rt].r){
if(t[rt].sum <= val) return t[rt].l;
else return t[rt].l + 1;
}
if(t[ls].mi <= val) return lower_bound(ls, val);
else return lower_bound(rs, val);
}
int query_min(int rt, int k){
if(t[rt].l == t[rt].r) return t[rt].sum;
pushdown(rt);
int mid = (t[rt].l + t[rt].r) >> 1;
if(k <= mid) return query_min(ls, k);
else return query_min(rs, k);
}
}seg;
void solve(){
cin >> n >> Q;
for(int i = 1 ; i <= n ; i ++) cin >> a[i];
seg.build(1, 1, n);
while(Q --){
int opt, x, y; cin >> opt >> x >> y;
if(opt == 1){
if(seg.query_sum(1, x, x) < y)
seg.set_max(1, x, y);
}else if(opt == 2){
int ans = 0;
x = max(x, seg.lower_bound(1, y));
while(x <= n){
int r = seg.find(1, seg.query_sum(1, 1, x - 1) + y);
y -= seg.query_sum(1, x, r);
ans += r - x + 1;
x = max(r + 2, seg.lower_bound(1, y));
}
cout << ans << '\n';
}
}
}
signed main(){
#ifndef ONLINE_JUDGE
freopen("D:\\in.txt", "r", stdin);
#endif
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
solve();
#ifndef ONLINE_JUDGE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}