推荐

USACO-26-1-铜组

黑大帅 2026-1-10 8:32:55 23 浏览 0 点赞 0 收藏

T1 chip change

题目描述

奶牛 Bessie 手里有 A 个 A 类筹码,以及 B 个 B 类筹码(0A,B1090\le A,B\le 10^9)。

她可以进行如下操作任意多次:

  • 如果当前 至少有 cBc_B 个 B 类筹码,就可以用 cBc_B 个 B 类筹码 兑换 cAc_A 个 A 类筹码。
    其中 1cA,cB1091\le c_A,c_B\le 10^9

现在问:最小的非负整数 xx 是多少,使得满足下面的“保证”条件:

在 Bessie 额外收到 xx 个随机筹码之后(每个筹码可能是 A 类或 B 类,分配方式未知),无论这 xx 个筹码具体怎么分配成 A/B,Bessie 都一定能通过若干次兑换操作,使得最终拥有的 A 类筹码数量 至少为 fAf_A0fA1090\le f_A\le 10^9)。

你需要对每个测试用例输出这个最小的 xx

输入格式

第一行是整数 TT,表示测试用例个数(1T1041\le T\le 10^4)。

接下来 TT 行,每行包含 5 个整数:

A, B, cA, cB, fAA,\ B,\ c_A,\ c_B,\ f_A

输出格式

对每个测试用例输出一行一个整数:对应的答案 xx

注意:数据范围很大,可能需要 64 位整数类型(例如 C/C++ 的 long long)。

样例

样例输入1:

2
2 3 1 1 6
2 3 1 1 4

样例输出1:

1
0

样例输入1:

5
0 0 2 3 5
0 1 2 3 5
1 0 2 3 5
10 10 2 3 5
0 0 1 1000000000 1000000000

样例输出2:

9
8
7
0
1000000000000000000

并解释(原文意思):

  • 第 1 组(A=B=0,cA=2,cB=3,fA=5A=B=0,c_A=2,c_B=3,f_A=5):
    Bessie 一开始没有筹码。只要她额外收到任意 9 个筹码,不管这 9 个里 A/B 怎么分配,她都能通过兑换最终得到至少 5 个 A。
    比如她收到 2 个 A 和 7 个 B,可以兑换两次得到 6 个 A(5\ge 5)。
    但如果只收到 8 个 B,则最多兑换 2 次得到 4 个 A(<5),所以 8 不够。

  • 第 4 组:她一开始就已经有足够多的 A,因此答案是 0。

评分提示

  • 输入 3:cA=cB=1c_A=c_B=1
  • 输入 4-5:所有用例的 x10x\le 10
  • 输入 6-7:cA=2,cB=3c_A=2, c_B=3
  • 输入 8-12:无额外限制

参考代码


#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using i128 = __int128; 

ll a, b, ca, cb, fa;


i128 cal(ll y, ll tot) {
	return (i128)tot - y + ((i128)y / cb) * ca;
}

bool chk(ll x) {
	ll tot = a + b + x;
	ll lim = b + x;
	
	i128 mn = cal(lim, tot);
	
	ll tg = cb - 1; 
	
	if (ca > cb) {
		
		ll r = b % cb;
		ll d = (tg - r + cb) % cb;
		ll y = b + d;
		if (y <= lim) mn = min(mn, cal(y, tot));
	} else {
		
		ll r = lim % cb;
		ll d = (r - tg + cb) % cb;
		ll y = lim - d;
		if (y >= b) mn = min(mn, cal(y, tot));
	}
	
	return mn >= fa;
}

void sol() {
	cin >> a >> b >> ca >> cb >> fa;
	ll l = 0, r = 2e18, ans = 2e18;
	
	while (l <= r) {
		ll md = l + (r - l) / 2;
		if (chk(md)) {
			ans = md;
			r = md - 1;
		} else {
			l = md + 1;
		}
	}
	cout << ans << "\n";
}

int main() {
	ios::sync_with_stdio(0); 
	cin.tie(0); 
	cout.tie(0);
	
	int t;
	cin >> t;
	while (t--) {
		sol();
	}
	return 0;
}

T2 COW

题目描述

Bessie 得到一个正整数 NN 和一个长度为 3N3N 的字符串 SS

字符串 SS 的生成方式如下:把 NN 个长度为 3 的字符串拼接起来,而每个长度为 3 的字符串都是 "COW" 的一个循环移位(cyclic shift),也就是说每段只能是下面三种之一:

  • "COW"
  • "OWC"
  • "WCO"

平方串(square string)

字符串 XX 被称为 平方串,当且仅当存在某个字符串 YY,使得:

X=Y+YX = Y + Y

其中 ++ 表示字符串拼接。 例如:

  • "COWCOW""CC" 是平方串(分别对应 Y="COW"Y="COW"Y="C"Y="C"

  • "COWO""OC" 不是平方串

操作

一次操作中,Bessie 可以从 SS 中删除任意一个子序列 TT,要求 TT 是一个平方串。

子序列指:从原串中删除若干个字符(可以删除 0 个),保持剩余字符的相对顺序得到的字符串。

目标

你需要判断:是否可以通过若干次操作,把 SS 变成空串

如果可以,还要输出一种删除方案。

参数 kk 与操作次数要求

题目还给一个参数 k{0,1}k\in\{0,1\}

设你输出的方案使用了 MM 次操作。

  • k=0k=0:必须保证 MM 等于最少可能操作次数(最优)。
  • k=1k=1:允许 MM 最多为 最少操作次数 + 1(几乎最优,多一次也行)。

输入格式

第一行包含两个整数:

  • TT:测试组数(1T1041\le T\le 10^4
  • kk:参数(0k10\le k\le 1

每个测试用例包含:

  1. 一行整数 NN1N1051\le N\le 10^5
  2. 一行字符串 SS,长度为 3N3N

保证所有测试中 NN 的总和不超过 10510^5

输出格式

对每个测试用例,按如下方式输出:

  • 如果无法把 SS 变成空串:输出一行 -1

  • 否则:

    • 第一行输出 MM:你的方案操作次数

    • 第二行输出 3N3N 个整数,用空格分隔
      ii 个整数 xix_i 表示:原串 SS 的第 ii 个字符是在第 xix_i 次操作中被删除的(要求 1xiM1\le x_i\le M

样例

样例输入1

3 1
3
COWOWCWCO
4
WCOCOWWCOCOW
6
COWCOWOWCOWCOWCOWC

样例输出1

-1
1
1 1 1 1 1 1 1 1 1 1 1 1
3
3 3 2 3 3 2 1 1 1 1 1 1 1 1 1 1 1 1

样例解释1

对于最后一个测试用例,最优(最少)操作次数是 2,因此当 k=1k=1 时,只要你的构造满足 M=2M=2M=3M=3 都会被判正确(允许比最优多 1 次)。

如果取 M=3M=3,下面给出一种可行方案:

  1. 第一次操作:删除最后 12 个字符。此时剩下字符串为 COWCOW

  2. 第二次操作:删除子序列 WW。此时剩下字符串为 COCO

  3. 第三次操作:删除所有剩余字符。最终变成空串。

样例输入2

3 0
3
COWOWCWCO
4
WCOCOWWCOCOW
6
COWCOWOWCOWCOWCOWC

样例输出2

-1
1
1 1 1 1 1 1 1 1 1 1 1 1
2
1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2

参考代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

int k;

bool chk1(const string& s){
	int h = (int)s.size() / 2;
	for(int i = 0; i < h; i++){
		if(s[i] != s[i + h]) return 0;
	}
	return 1;
}

string work(const string& s, int st, char c){
	char a = 0, b = 0;
	int t = 0;
	string r;
	for(int j = 0; j < 3; j++){
		char x = s[st + j];
		if(x == c) continue;
		if(t == 0) a = x;
		else b = x;
		t++;
	}
	r += a;
	r += b;
	return r;
}

char pickc(const string& s, int x1, int x2){
	string t = "COW";
	for(char c : t){
		if(work(s, x1, c) == work(s, x2, c)) return c;
	}
	return 'C';
}

void sol(){
	int n;
	cin >> n;	
	string s;
	cin >> s;
	
	if(n & 1){
		cout << -1 << "\n";
		return;
	}
	
	int m = 3 * n;
	
	if(chk1(s)){
		cout << 1 << "\n";
		for(int i = 0; i < m; i++){
			cout << 1 << (i + 1 == m ? '\n' : ' ');
		}
		return;
	}
	
	cout << 2 << "\n";
	
	int h = n / 2;
	vector<int> ans(m, 2);
	
	for(int i = 0; i < h; i++){
		int x1 = 3 * i;
		int x2 = 3 * (i + h);
		
		char c = pickc(s, x1, x2);
		
		for(int j = 0; j < 3; j++){
			ans[x1 + j] = (s[x1 + j] == c ? 1 : 2);
			ans[x2 + j] = (s[x2 + j] == c ? 1 : 2);
		}
	}
	
	for(int i = 0; i < m; i++){
		cout << ans[i] << (i + 1 == m ? '\n' : ' ');
	}
}

int main(){
	ios::sync_with_stdio(0); 
	cin.tie(0); 
	cout.tie(0);
	
	int t;
	cin >> t >> k;
	while(t--) 
	{
		sol();
	}
	
	return 0;
}

T3 photo

题目描述

农夫 John 在一块“魔法草地”里看牛,想给牛群的某些子集拍照。

这块草地可以看成一个 N×NN \times N 的网格(1N5001 \le N \le 500),每个格子上都有一头固定不动的牛

农夫的相机可以拍摄草地中任意一个 K×KK \times K 的正方形区域(必须完全在草地内),其中1Kmin(N,25)1 \le K \le \min(N,25)

美丽值与吸引力

每头牛都有一个“美丽值”(beauty),范围在 01060 \sim 10^6

一张照片的“吸引力指数”(attractiveness index)定义为:

照片中所有牛的美丽值之和(也就是该 K×KK \times K 方块内的总和)

开始时每头牛的美丽值都是 0,所以任何照片的吸引力指数一开始都为 0

更新操作

接下来会发生 QQ 次变化(1Q3×1041 \le Q \le 3\times 10^4):

每次变化会指定一个格子 (r,c)(r,c),该位置的牛因为吃草,美丽值会增加到一个更大的新值(题目输入给的是新值,不是增量):

  • 输入:r,c,vr, c, v
    表示第 rr 行第 cc 列的美丽值被更新为 vv
  • 保证:新的 vv 严格大于该位置之前的美丽值

在每一次更新之后,农夫想知道:

此时任意一个 K×KK \times K 照片中,吸引力指数的最大值是多少

也就是:更新后,所有可能的 K×KK \times K 方块求和,输出其中最大那个和。

输入格式

  • 第一行:N,KN, K
  • 第二行:QQ
  • 接下来 QQ 行:每行 r,c,vr, c, v 其中 1r,cN1 \le r,c \le N1v1061 \le v \le 10^6

输出格式

输出 QQ 行:第 ii 行是第 ii 次更新后,最大吸引力指数(最大 K×KK \times K 区域和)。

样例

输入样例1:

4 2
3
2 2 11
3 4 3
3 1 100

输出样例1:

11
11
111

输入样例2:

3 1
3
2 2 3
2 2 5
2 2 7

输出样例2:

3
5
7

参考代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

int a[505][505];
ll sm[505][505];
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	
	int n, k;
	cin >> n >> k;
	
	int q;
	cin >> q;
	
	
	int m = n - k + 1;
	
	ll mx = 0;
	
	while (q--) {
		int r, c, v;
		cin >> r >> c >> v;
		
		int od = a[r][c];
		int d = v - od;
		a[r][c] = v;
		
		int x1 = max(1, r - k + 1);
		int x2 = min(r, m);
		int y1 = max(1, c - k + 1);
		int y2 = min(c, m);
		
		for (int i = x1; i <= x2; i++) {
			for (int j = y1; j <= y2; j++) {
				sm[i][j] += d;
				if (sm[i][j] > mx) mx = sm[i][j];
			}
		}
		
		cout << mx << "\n";
	}
	
	return 0;
}

评论

0 条
还没有评论。