【记录】AT_abc441模拟赛

作为复建还算不错的一场。


AT_abc441_c ABC441C Sake or Water - 洛谷 (luogu.com.cn)

我必须要说一下这个 c,卡了我 20 分钟,排完序才发现前 K 个要从大到小喝。

首先,最坏情况就是所有清酒都在最小容量的 K 个杯子中。

然后,我们按最优方法饮用,因为无论大小容量,喝一杯就只算一杯

肯定喝大杯的划算,这样同样一杯的代价能喝到更多的清酒。

所以方法就是把大的都喝完。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

#define int long long 
const int N = 3e5 + 10;
int a[N];

void work() {
	int n, K, X;
	cin >> n >> K >> X;
	for (int i = 1; i <= n; i ++) {
		cin >> a[i];
	}
	sort (a + 1, a + n + 1);
	
	int sum = 0;
	for (int i = K; i >= 1; i --) {
		sum += a[i];
		if (sum >= X) {
			cout << (n - K + K - i + 1) << "\n";
			return ;
		}
	}
	cout << "-1\n";
}

signed main () {
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	work();
	
	return 0;
}

AT_abc441_d ABC441D Paid Walk - 洛谷 (luogu.com.cn)

若只到没话说,随便 dfs 就能过。

AT_abc441_e ABC441E A > B substring - 洛谷 (luogu.com.cn)

也挺简单,前缀和+树状数组。

假设选一段 那么就有要求:

数组是从字符串起始到 位置(包括)的 'A' 字母个数累计, 同理)

移项

从小到大遍历 ,以 结尾的段的数量就是

用树状数组即可,常数小,总时间复杂度为

注意一下因为 可能为负数,树状数组不能存 的下标。

所以下标统一 + n 就好,我为了保险 + 2 * n。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 5e5 + 10;
LL a[N], b[N];
char s[N]; 
LL c[N * 4];
int n;

void add(int x, LL d) {
	for (int i = x; i <= 4 * n; i += i & -i) {
		c[i] += d;
	}
}
LL query(int x) {
	LL sum = 0;
	for (int i = x; i >= 1; i -= i & -i) {
		sum += c[i];
	}
	return sum;
}

int main () {
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    cin >> n;
    cin >> s;
    a[0] = b[0] = 0;
    LL t;
    
    for (int i = 1; i <= n; i ++) {
        t = (s[i - 1] == 'A') ? 1 : 0;
        a[i] = a[i - 1] + t;
        t = (s[i - 1] == 'B') ? 1 : 0;
        b[i] = b[i - 1] + t;
    }
    
    LL ans = 0;
    memset(c, 0, sizeof(c));
    add(2 * n, 1);
    for (int i = 1; i <= n; i ++) {
        t = a[i] - b[i] + n * 2;
        ans += query(t - 1);
        add(a[i] - b[i] + n * 2, 1);
    }
    
    cout << ans << "\n";
    
    return 0;
}

AT_abc441_f ABC441F Must Buy - 洛谷 (luogu.com.cn)

我此前还未听说过前后缀 dp,知道了就很简单。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 1005;
const int M = 5e4 + 5;

LL dpa[N][M], dpb[N][M];  
int p[N]; LL v[N];
char s[N];

int main () {
	ios::sync_with_stdio(false);
	cin.tie(0);
	
	int n, m;
	cin >> n >> m;
	
	for (int i = 1; i <= n; i ++) {
		cin >> p[i] >> v[i];
	}
	
	memset(dpa, 0, sizeof(dpa));
	for (int i = 1; i <= n; i ++) {
		for (int j = 0; j <= m; j ++) {
			dpa[i][j] = dpa[i - 1][j];
		}
		for (int j = p[i]; j <= m; j ++) {
			dpa[i][j] = max(dpa[i][j], dpa[i - 1][j - p[i]] + v[i]);
		}
	}
	
	memset(dpb, 0, sizeof(dpb));
	for (int i = n; i >= 1; i --) {
		for (int j = 0; j <= m; j ++) {
			dpb[i][j] = dpb[i + 1][j];
		}
		for (int j = p[i]; j <= m; j ++) {
			dpb[i][j] = max(dpb[i][j], dpb[i + 1][j - p[i]] + v[i]);
		}
	}
	
	LL mxans = dpa[n][m];
	
	for (int i = 1; i <= n; i ++) {
		LL mxno = 0, mxmu = 0;
		for (int j = 0; j <= m; j ++) {
			mxno = max(mxno, dpa[i - 1][j] + dpb[i + 1][m - j]);
		}
		for (int j = 0; j <= m - p[i]; j ++) {
			mxmu = max(mxmu, v[i] + dpa[i - 1][j] + dpb[i + 1][m - j - p[i]]);
		}
		
		if (mxmu < mxans) {   // 强制选 < 最优解,那么最优解一定不选 
			cout << "C";
		}
		else if (mxno < mxans) { // 不选 < 最优解,那么最优解一定选 
			cout << "A";
		}
		else {  // 选不选都是最优解,那随便 
			cout << "B";
		}
	}
	
	cout << "\n";
	
	return 0;
}

AT_abc441_g ABC441G Takoyaki and Flip - 洛谷 (luogu.com.cn)

典中典懒标记线段树,除了难调以外没难度。

但也是真的很难调。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

typedef long long LL;
#define lc(p) (p << 1)
#define rc(p) ((p << 1) | 1)
const int N = 2e5 + 10;

struct trnode {
    int l, r;
    LL mxc;
    int type;    // 区间状态:1全正,2混合,3全反
    LL ltg;      // 增加 x tag
    bool has;    // 清空标记
    bool flip;   // 翻转标记
} tr[N * 4];

void pushup(int p) {
    tr[p].mxc = max(tr[lc(p)].mxc, tr[rc(p)].mxc);
    if (tr[lc(p)].type == 1 && tr[rc(p)].type == 1) {
        tr[p].type = 1;
    }
    else if (tr[lc(p)].type == 3 && tr[rc(p)].type == 3) {
        tr[p].type = 3;
    }
    else {
        tr[p].type = 2;
    }
}

void pushdown(int p) {
    // 先处理清空标记
    if (tr[p].has) {
        tr[lc(p)].mxc = 0;
        tr[rc(p)].mxc = 0;
        tr[lc(p)].ltg = 0;
        tr[rc(p)].ltg = 0;
        tr[lc(p)].has = true;
        tr[rc(p)].has = true;
        tr[p].has = false;
    }
    
    // 处理翻转标记
    if (tr[p].flip) {
        // 翻转左孩子
        tr[lc(p)].type = 4 - tr[lc(p)].type;
        tr[lc(p)].flip ^= 1;
        // 翻转右孩子
        tr[rc(p)].type = 4 - tr[rc(p)].type;
        tr[rc(p)].flip ^= 1;
        tr[p].flip = false;
    }
    
    // 处理加法标记
    if (tr[p].ltg != 0) {
        if (tr[lc(p)].type != 3) {
            tr[lc(p)].mxc += tr[p].ltg;
            tr[lc(p)].ltg += tr[p].ltg;
        }
        if (tr[rc(p)].type != 3) {
            tr[rc(p)].mxc += tr[p].ltg;
            tr[rc(p)].ltg += tr[p].ltg;
        }
        tr[p].ltg = 0;
    }
}

void build(int p, int l, int r) {
    tr[p] = {l, r, 0, 1, 0, false, false};
    if (l == r) {
        return;
    }
    int mid = (l + r) >> 1;
    build(lc(p), l, mid);
    build(rc(p), mid + 1, r);
    pushup(p);
}

void update_add(int p, int l, int r, LL x) {
    if (r < tr[p].l || tr[p].r < l) {
        return;
    }
    if (l <= tr[p].l && tr[p].r <= r) {
        if (tr[p].type != 3) {  // 反面朝上的盘子不加章鱼烧
            tr[p].mxc += x;
            tr[p].ltg += x;
        }
        return;
    }
    pushdown(p);
	update_add(lc(p), l, r, x);
	update_add(rc(p), l, r, x);
    pushup(p);
}

void update_flip(int p, int l, int r) {
    if (r < tr[p].l || tr[p].r < l) {
        return;
    }
    if (l <= tr[p].l && tr[p].r <= r) {
        // 清空所有章鱼烧
        tr[p].mxc = 0;
        tr[p].ltg = 0;
        tr[p].has = true;
        // 翻转状态
        tr[p].type = 4 - tr[p].type;
        tr[p].flip ^= 1;
        return;
    }
    pushdown(p);
    update_flip(lc(p), l, r);
    update_flip(rc(p), l, r);
    pushup(p);
}

LL query(int p, int l, int r) {
    if (r < tr[p].l || tr[p].r < l) {
        return 0;
    }
    if (l <= tr[p].l && tr[p].r <= r) {
        return tr[p].mxc;
    }
    pushdown(p);
	return max(query(lc(p), l, r), query(rc(p), l, r));
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int n, Q;
    cin >> n >> Q;
    
    build(1, 1, n);
    for (int i = 1; i <= Q; i++) {
        int opt;
        cin >> opt;
        if (opt == 1) {
            int l, r;
            LL x;
            cin >> l >> r >> x;
            update_add(1, l, r, x);
        }
        else if (opt == 2) {
            int l, r;
            cin >> l >> r;
            update_flip(1, l, r);
        }
        else {
            int l, r;
            cin >> l >> r;
            cout << query(1, l, r) << "\n";
        }
    }
    
    return 0;
}