Codeforces Round #821 (Div. 2)

A. Consecutive Sum

题意:

给定长度为 n n n 的数组,如果 i = j ( m o d k ) i=j(modk) i=j(modk) ,可以交换 a i a_i ai a j a_j aj,最多进行 k k k 次操作,求长度为 k k k 的连续序列最大值。

解析:

将数组按照对 k k k取余进行分组,然后取出每一组的最大值

代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e2+10;
vector<ll> a[maxn];
int n, k;
void solve(){
	cin >> n >> k;
	for(int i = 0; i <= 100; i++){
		a[i].clear();
		a[i].push_back(0);
	}

	for(int i = 1; i <= n; i++){
		ll x;
		cin >> x;
		a[i%k].push_back(x);
	}
	ll sum = 0;
	for(int i = 0; i < k; i++){
		sum += *max_element(a[i].begin(), a[i].end());
	}
	cout << sum << endl;
}
int main(){
	int T;
	cin >> T;
	while(T--)
		solve();
	return 0;	
}


B. Rule of League

题意:

n n n的人比赛。 1 1 1 2 2 2比赛,胜者与 3 3 3比赛,然后胜者与 4 4 4比赛,共 n − 1 n-1 n1场比赛。
给定 x , y x,y x,y,是否存在方案,使所有的胜利场数为 x x x y y y。若存在,给出方案。

解析:

显然 x , y x,y x,y中有且仅有一个零,否则不存在合法方案。不妨 x ≠ 0 , y = 0 x \neq 0,y=0 x=0,y=0。其次, ( n − 1 ) % x = 0 (n-1)\%x = 0 (n1)%x=0。方案为:第 i i i各人连胜 x x x次,然后第 i + x i+x i+x人连胜 x x x次,特判一下 i = 1 i=1 i=1

代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int x, y, n;
void solve(){
	cin >> n >> x >> y;
	if((x==0&&y==0) || (x!=0&&y!=0)){
		cout << -1 << endl;
		return;
	}
	int len = max(x, y);
	if((n-1)%len != 0){
		cout << -1 << endl;
		return;
	}
	for(int i = 1; i <= n;){
		for(int j = 1; j <= len; j++)
			cout << i << " ";
		if(i == 1)
			i++;
		i += (len);
	}
	cout << endl;
	return ;
}
int main(){
	int T;
	cin >> T;
	while(T--)
		solve();
}


C. Parity Shuffle Sorting

题意:

给定长度为 n n n的数组,每次操作选择 l , r l,r l,r,若 a l + a r a_l+a_r al+ar为偶数,令 a l = a r a_l = a_r al=ar;若 a l + a r a_l+a_r al+ar为奇数,令 a r = a l a_r = a_l ar=al。求方案,使序列不降。

解析:

如果所有数都相同,也是不降序列。首先选择 l = 1 , r = n l=1,r=n l=1,r=n,使 a 1 = = a n a_1 = =a_n a1==an,然后对 a i a_i ai 2 ≤ i ≤ n − 1 2 \le i \le n-1 2in1,选择 a 1 a_1 a1 a n a_n an。需要 n − 1 n-1 n1次操作。

代码:
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
int n, t, x, a[100005];
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	for(cin >> t; t--;){
		cin >> n;
		for(int i = 1; i <= n; i++)
			cin >> a[i];
		cout << n - 1 << endl;
		if(n > 1)
			cout << 1 << ' ' << n << endl;
		x = (a[1] + a[n]) % 2 ? a[1] : a[n];
		for(int i = 2; i < n; i++){
			if((x + a[i]) % 2)
				cout << 1 << ' ' << i << endl;
			else 
				cout << i << ' ' << n << endl;
		}
	}
	return 0;
}


D1. Zero-One (Easy Version)

题意:

给定两个长度相同的01串 a , b a,b a,b,每次可以选定一个串的两个位置 l , r l,r l,r,01翻转。如果选择的位置相邻即 l + 1 = r l+1=r l+1=r,则翻转的代价为 x x x;不相邻的翻转的代价为 y y y ( x ≥ y ) (x \ge y) (xy)。询问使两个串相同的最小代价。

解析:

每次能调整两个位置,如果需要调整的位置为奇数,显然不可能,所以需要调整的位置为偶数。
调整一次相邻位置的代价 x x x可以用调整两次不相邻位置的代价 2 y 2y 2y代替。
如果需要调整的位置数大于等于4,可以一直花费代价 y y y

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
const int INF = 0x3f3f3f3f;
string a, b;
int c[maxn];
int n, x, y;
void solve(){
	cin >> n >> x >> y;
	cin >> a >> b;
	int cnt = 0;
	int l = INF, r = -1;
	for(int i = 0; i < n; i++){
		c[i] = (a[i]==b[i])?0:1;
		cnt += c[i];
		if(c[i]){
			l = min(l, i);
			r = max(r, i);
		}
	}
	if(cnt%2 == 1){
		cout << -1 << endl;
		return;
	}
	if(l+1 == r)
		cout << min(x, 2*y) << endl;
	else
		cout << cnt/2*y << endl;
	return; 		
}
int main(){
	int T;
	cin >> T;
	while(T--)
		solve();
	return 0;
}


D2. Zero-One (Hard Version)

题意:

同上,取消条件 x ≥ y x \ge y xy,增加条件 n ≤ 5000 n \le 5000 n5000

解析:

修改一次相邻位置的代价 x x x可以用修改两次不相邻位置的代价 2 y 2y 2y代替。修改一次不相邻位置 ( l , r ) (l,r) (l,r) 可以用修改 ( r − l ) (r-l) (rl)次相邻位置的代价 x ( r − l ) x(r-l) x(rl)代替。
预处理所有修改的位置,然后DP。
d p i j = { d p i + 2 , j + c o s t ( i , i + 1 ) d p i + 1 , j − 1 + c o s t ( i , j ) d p i , j − 2 + c o s t ( j − 1 , j ) dp_{ij}=\left\{ \begin{aligned} dp_{i+2,j}+cost(i,i+1) \\ dp_{i+1, j-1}+cost(i, j) \\ dp_{i, j-2}+cost(j-1, j)\\ \end{aligned} \right. dpij= dpi+2,j+cost(i,i+1)dpi+1,j1+cost(i,j)dpi,j2+cost(j1,j)

代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e3+10;
const ll INF = 0x3f3f3f3f3f3f3f3f;
ll x, y, n;
string a, b;
ll dp[maxn][maxn];
vector<int> pos; 
ll cost(int l, int r){
	if(l+1 == r)
		return min(2*y, x);
	else
		return min(y, x*(r-l));
}
void DP(int x){
	for(int i = 0; i <= x; i++)
		for(int j = 0; j <= x; j++)
			dp[i][j] = 0;
	for(int len = 2; len <= x; len++){
		for(int l = 0; l+len <= x; l++){
			int r = l+len-1;
			ll res = INF;
			res = min(res, dp[l+2][r]+cost(pos[l], pos[l+1]));
			res = min(res, dp[l][r-2]+cost(pos[r-1], pos[r]));
			res = min(res, dp[l+1][r-1]+cost(pos[l], pos[r]));
			dp[l][r] = res;
		}
	}
}
void solve(){
	cin >> n >> x >> y;
	cin >> a >> b;
	for(int i = 0; i <= n; i++)
		for(int j = 0; j <= n; j++)
			dp[i][j] = -1;
	
	pos.clear();
	for(int i = 0; i < n; i++)
		if(a[i] != b[i])
			pos.push_back(i);
	if(pos.size()%2){
		cout << -1 << endl;
		return;
	}
	else if(pos.size() == 0){
		cout << 0 << endl;
		return;
	}
	else if(pos.size() == 2){
		if(pos[0]+1 == pos[1])
			cout << min(2*y, x) << endl;
		else
			cout << min(y, x*(pos[1]-pos[0])) << endl;
	}
	else if(y <= x)
		cout << pos.size()/2*y << endl;
	else{
		DP(pos.size());
		cout << dp[0][pos.size()-1] << endl;
	}
}
int main(){
	int T;
	cin >> T;
	while(T--)
		solve();
	return 0;
} 


E. Conveyor

题意:

每个格子上都有一个传送带,初始向右。每秒在 ( 0 , 0 ) (0,0) (0,0)处放一个物品。当传送带传送完一次物品后,传送带的方向发生改变。向右的变为向下,向下的变为向右。询问 t t t 时刻,坐标 ( x , y ) (x,y) (x,y)的传送带上是否有物品。

解析:

求出 t t t秒内,每个传送带经过了多少物品 f ( t , x , y ) f(t, x, y) f(t,x,y),答案为 f ( t , x , y ) − f ( t − 1 , x , y ) f(t,x,y)-f(t-1,x,y) f(t,x,y)f(t1,x,y)是否为0。注意,从 ( 0 , 0 ) (0,0) (0,0) ( x , y ) (x,y) (x,y)花费 x + y x+y x+y的时间。

代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 200;
int q;
ll dp[maxn][maxn];

ll f(ll t, ll x, ll y){
	memset(dp, 0, sizeof(dp));
	dp[0][0] = max(t-(x+y)+1, 0ll);
	for(int i = 0; i <= x; i++)
		for(int j = 0; j <= y; j++){
			dp[i+1][j] += dp[i][j]/2;
			dp[i][j+1] += dp[i][j]-dp[i][j]/2;
		}
	return dp[x][y];
}
int main(){
	cin >> q;
	for(int i = 1; i <= q; i++){
		ll t, x, y;
		cin >> t >> x >> y;
		ll ans = f(t, x, y)-f(t-1, x, y);
		if(ans > 0)
			cout << "YES" << endl;
		else
			cout << "NO" << endl;
	}
	return 0;
}

https://zhuanlan.zhihu.com/p/566175996

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值