Codeforces Round #683 (Div. 2) A-D题解

A

题意
给你 n n n包糖果,第 i i i包里面有 i i i颗糖果,第 i i i次操作可以选定其中一包糖果,将其余包的糖果数加 i i i,输出使所有包的糖果数相等的最少操作次数和每次操作的索引值。

分析
i i i次操作将除了选定包的糖果数加 i i i等价于将选定包的糖果数减去 i i i,因此第1次操作选1,第二次选2,…即可。

代码

#include<bits/stdc++.h>
#define ll long long
#define FULL(x,y) memset(x,y,sizeof(x))
#define pb push_back
using namespace std;
 
int t,n;
 
int main() {
	cin>>t;
	while(t--) {
		cin>>n;
		cout<<n<<endl;
		for(int i=1;i<=n;i++) cout<<i<<' ';
		cout<<endl;
	}
	return 0;
}

B

题意
给定一个 n × m n \times m n×m的矩阵 a a a,每次操作可以选择相邻的两个元素,将这两个元素乘 − 1 -1 1,问能得到的矩阵所有元素的和最大是多少。

分析
若矩阵中含有偶数个负数,那么总可以把这偶数个负数变正(不断乘 − 1 -1 1把负数集中在一起);若矩阵中含有奇数个负数又没有 0 0 0,那么最大和应为数字绝对值的和减去最小绝对值 × 2 \times2 ×2,若含 0 0 0,可以用 0 0 0将负数变正,最大和仍为数字绝对值的和。

代码

#include<bits/stdc++.h>
#define ll long long
#define FULL(x,y) memset(x,y,sizeof(x))
#define pb push_back
using namespace std;
 
int t,n,m;
int a[15][15];
 
int main() {
	cin>>t;
	while(t--) {
		cin>>n>>m;
		int fl=0,sum=0,minnum=1e9,cnt=0;
		for(int i=1;i<=n;i++) {
			for(int j=1;j<=m;j++) {
				cin>>a[i][j];
				if (a[i][j]<0) {
					a[i][j]=-a[i][j];
					cnt++;
				}
				if (a[i][j]==0) fl=1;
				sum+=a[i][j];
				minnum=min(minnum,a[i][j]);
			}
		}
		if (cnt&1) {
			if (!fl) cout<<sum-2*minnum<<endl;
			else cout<<sum<<endl;
		}
		else cout<<sum<<endl;
	}
	return 0;
}

C

题意
有一个容量为 W W W的背包, n n n件物品,第 i i i件物品的重量为 w i {w_i} wi,问能否从中找出一些物品,使物品的容量之和在 [ ⌈ W 2 ⌉ , W ] \left[ {\left\lceil {\frac{W}{2}} \right\rceil ,W} \right] [2W,W]之间,输出物品数量和索引值。
数据范围: 1 ≤ n ≤ 200000 , 1 ≤ W ≤ 1 0 18 , 1 ≤ w i ≤ 1 0 9 1 \le n \le 200000,1 \le W \le {10^{18}},1 \le {w_i} \le {10^9} 1n200000,1W1018,1wi109

分析
看数据范围不能用传统的背包来做,考虑将 w i {w_i} wi的值从小到大排序,从前往后遍历求和,记和为 s u m sum sum,对当前的 s u m sum sum来说,有三种情况:当 s u m < ⌈ W 2 ⌉ sum < \left\lceil {\frac{W}{2}} \right\rceil sum<2W;继续累加 s u m sum sum,当 s u m ∈ [ ⌈ W 2 ⌉ , W ] sum \in \left[ {\left\lceil {\frac{W}{2}} \right\rceil ,W} \right] sum[2W,W],直接break输出;当 s u m > W sum > W sum>W,此时有 w i > W − ⌈ W 2 ⌉ + 1 ≥ ⌈ W 2 ⌉ {w_i} > W - \left\lceil {\frac{W}{2}} \right\rceil + 1 \ge \left\lceil {\frac{W}{2}} \right\rceil wi>W2W+12W,故若 w i ∈ [ ⌈ W 2 ⌉ , W ] {w_i} \in \left[ {\left\lceil {\frac{W}{2}} \right\rceil ,W} \right] wi[2W,W],直接输出 w i {w_i} wi就行,否则输出-1,后面的数也无法满足要求。

代码

#include<bits/stdc++.h>
#define ll long long
#define FULL(x,y) memset(x,y,sizeof(x))
#define pb push_back
using namespace std;

const int N=200005;
int t,n;
ll w;

struct node {
	ll x;
	int id;
	bool operator <(const node& no) const {
		return x<no.x;
	}
}a[N];

int main() {
	cin>>t;
	while(t--) {
		cin>>n>>w;
		for(int i=1;i<=n;i++) {
			cin>>a[i].x;
			a[i].id=i;
		}
		ll sum=0;
		sort(a+1,a+1+n);
		int ans,fl=0;
		for(int i=1;i<=n;i++) {
			sum+=a[i].x;
			if (sum>=1LL*ceil(w/2.0) && sum<=w) {
				ans=i;
				fl=1;
				break;
			}
			if (sum>w) {
				if (a[i].x>=1LL*ceil(w/2.0) && a[i].x<=w) {
					ans=i;
					fl=2;
				}
				break;
			}
		}
		if (!fl) cout<<-1<<endl;
		else if (fl==1) {
			cout<<ans<<endl;
			for(int i=1;i<=ans;i++) cout<<a[i].id<<' ';
			cout<<endl;
		}
		else {
			cout<<1<<endl;
			cout<<a[ans].id<<endl;
		}
	}
	return 0;
}

D

题意
给你两个字符串 s 1 {s_1} s1 s 2 {s_2} s2,定义 S ( A , B ) = 4 ⋅ L C S ( A , B ) − ∣ A ∣ − ∣ B ∣ S({A},{B}) = 4 \cdot LCS({A},{B}) - \left| A \right| - \left| B \right| S(A,B)=4LCS(A,B)AB,其中 A A A s 1 {s_1} s1的子串, B B B s 2 {s_2} s2的子串, L C S ( A , B ) LCS({A},{B}) LCS(A,B) A A A B B B的最长公共子序列,求 S ( A , B ) S({A},{B}) S(A,B)的最大值。
数据范围: 1 ≤ ∣ s 1 ∣   , ∣ s 2 ∣ ≤ 5000 1 \le \left| {{s_1}} \right|\,,\left| {{s_2}} \right| \le 5000 1s1,s25000

分析
很明显能看出是一个标准的动态规划,令 d p [ i ] [ j ] dp[i][j] dp[i][j]表示以 s 1 {s_1} s1的前 i i i个字符和 s 2 {s_2} s2的前 j j j个字符结尾的最大 S S S值,则有如下的状态转移方程:
{ d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 2 , s [ i ] = s [ j ] d p [ i ] [ j ] = max ⁡ ( 0 , max ⁡ ( d p [ i ] [ j − 1 ] , d p [ i − 1 ] [ j ] ) − 1 ) , s [ i ] ≠ s [ j ] \left\{ \begin{array}{l} dp[i][j] = dp[i - 1][j - 1] + 2,\quad s[i] = s[j]\\ dp[i][j] = \max (0,\max (dp[i][j - 1],dp[i - 1][j]) - 1),\quad s[i] \ne s[j] \end{array} \right. {dp[i][j]=dp[i1][j1]+2,s[i]=s[j]dp[i][j]=max(0,max(dp[i][j1],dp[i1][j])1),s[i]=s[j]
初始化 d p dp dp数组为0,最后的答案即为 max ⁡ i , j d p [ i ] [ j ] \mathop {\max }\limits_{i,j} dp[i][j] i,jmaxdp[i][j]

代码

#include<bits/stdc++.h>
#define FULL(x,y) memset(x,y,sizeof(x))
#define ll long long
#define pb push_back
using namespace std;

const int N=5005;
int n,m;
string s1,s2;
int dp[N][N];

int main() {
	cin>>n>>m>>s1>>s2;
	int ans=0;
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=m;j++) {
			if (s1[i-1]==s2[j-1]) {
				dp[i][j]=dp[i-1][j-1]+2;
			}
			else {
				dp[i][j]=max(dp[i-1][j],dp[i][j-1])-1;
				dp[i][j]=max(dp[i][j],0);
			}
			ans=max(ans,dp[i][j]);
		}
	}
	cout<<ans;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值