Codeforces Round #683 (Div. 2, by Meet IT)
传送门(点击传送)
A. Add Candies
题意:
有 m 个包,第 i 个包初始有 i 个糖果,现在可以进行如下操作,当你进行第 j 次操作时,选择一个包 x ,除第 x 个包外每个包增加 j 个糖果,现在让你将每个包的糖果数量操作到相等,请输出你的操作次数以及依次输出每次选择的包。( t 组数据)
思路:
想法当然是让越靠前的包增加的越多,而且因为是等差数列差一,而且增加也是每次多一个,所以从 1 到 n 依次选择包即可。
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t,n;
cin>>t;
while(t--){
cin>>n;
cout<<n<<endl;
for(int i=1;i<=n;i++){
cout<<i<<" ";
}
cout<<endl;
}
return 0;
}
B. Numbers Box
题意:
有一个 n 行 m 列的矩阵,现在你可以进行如下操作,每次操作选两个相邻的元素,让这两个元素分别等于这两个元素的值乘以 -1 ,现在让 X 等于矩阵所有的元素之和。现在想知道经过操作后 X 的值最大为多少。找出这个最大值。操作次数不限。( t 组数据)
思路:
负号可以由相邻的元素进行传递,所以这道题统计原矩阵中有多少个负数即可。若有偶数个负数或者有1个 0 出现,那么这个矩阵我们就可以通过操作让所有的数变为非负数,答案就是所有的元素的绝对值之和。如果有奇数个负数,那么我们可以通过传递让绝对值最小的数为负数即可,答案就是所有元素的绝对值之和减去 2 乘以绝对值最小的数的绝对值。
代码:
#include<bits/stdc++.h>
using namespace std;
int num[105][105];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t,n,m;
cin>>t;
while(t--){
cin>>n>>m;
int sum=0,cont=0;
int minn=0x7fffffff;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>num[i][j];
if(num[i][j]<0){
cont++;
num[i][j]*=-1;
}
sum+=num[i][j];
minn=min(minn,num[i][j]);
}
}
if(minn==0){
cout<<sum<<endl;
}else{
if(cont%2)cout<<sum-2*minn<<endl;
else cout<<sum<<endl;
}
}
return 0;
}
C. Knapsack
题意:
有一个容量为 W W W 的包和 n 个物品,每个物品的质量为 w i w_i wi,现在规定我们这个包至少要放 ⌈ W 2 ⌉ \left \lceil \frac{W}{2} \right \rceil ⌈2W⌉ 的物品,最多不能放超过 W W W 的物品,问有可选的方案符合题目要求吗,若有则输出放入物品的个数和从小到大依次输出物品序号。如果没有可选方案则输出 -1 。( t 组数据)
思路:
贪心,给物品从大到小排序,然后从大物品依次枚举,若放入后总质量大于 W W W则不放该物品,若放入后仍然不达 ⌈ W 2 ⌉ \left \lceil \frac{W}{2} \right \rceil ⌈2W⌉ 则放入该物品并继续枚举下一个,若放入后位于 ⌈ W 2 ⌉ \left \lceil \frac{W}{2} \right \rceil ⌈2W⌉ 和 W W W 之间则停止,所放入的为一种可选方案。注意判断若所有物品都放入都不达 ⌈ W 2 ⌉ \left \lceil \frac{W}{2} \right \rceil ⌈2W⌉ 则不存在可选方案。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
struct node{
int loc,v;
}item[maxn];
int ans[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int t,n;
ll w,ww;
cin>>t;
while(t--){
cin>>n>>w;
ww=(w+1)/2;
for(int i=1;i<=n;i++){
cin>>item[i].v;
item[i].loc=i;
}
sort(item+1,item+1+n,[](const node &a,const node &b){
return a.v>b.v;});
ll sum=0;
int st=0;
for(int i=1;i<=n;i++){
sum+=1ll*item[i].v;
st++;
ans[st]=item[i].loc;
if(sum>w){
sum-=1ll*item[i].v;
st--;
}
}
if(st==0 || sum<ww) cout<<-1<<endl;
else{
cout<<st<<endl;
sort(ans+1,ans+1+st);
for(int i=1;i<=st;i++){
cout<<ans[i]<<" ";
}
cout<<endl;
}
}
return 0;
}
D. Catching Cheaters
题意:
有两个序列 A 和 B ,并且有 C 是 A 的子序列, D 是 B 的子序列。现在规定 S ( C , D ) = 4 ⋅ L C S ( C , D ) − ∣ C ∣ − ∣ D ∣ S(C,D)=4·LCS(C,D)-\left | C\right |-\left | D\right | S(C,D)=4⋅LCS(C,D)−∣C∣−∣D∣,其中 L C S ( C , D ) LCS(C,D) LCS(C,D)是 C 和 D 的最长公共子序列,求对于序列 A 和 B 的最大 S ( C , D ) S(C,D) S(C,D)是多少。
思路:
动态规划,我们在最长公共子序列的dp基础上进行延申。不理解最长公共子序列求法的小伙伴可先先看这里:OI-WIKI——动态规划基础。当有 A [ i ] = = B [ j ] A[i]==B[j] A[i]==B[j] 的时候,我们对于原最长公共子序列的状态转移是 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 1 dp[i][j]=dp[i-1][j-1]+1 dp[i][j]=dp[i−1][j−1]+1 ,那么对于当前这道题,如果 A [ i ] = = B [ j ] A[i]==B[j] A[i]==B[j] 时,我们的 L C S ( C , D ) LCS(C,D) LCS(C,D) 的长度相当于增加了一,对应的 4 ⋅ L C S ( C , D ) 4·LCS(C,D) 4⋅LCS(C,D) 就增加了 4,但是我们对应的要减去的 C 序列和 D 序列的长度也增加了一,所以我们的状态转移方程就是 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] + 4 − 1 − 1 = d p [ i − 1 ] [ j − 1 ] + 2 dp[i][j]=dp[i-1][j-1]+4-1-1=dp[i-1][j-1]+2 dp[i][j]=dp[i−1][j−1]+4−1−1=dp[i−1][j−1]+2 。当 A [ i ] = = B [ j ] A[i]==B[j] A[i]==B[j] 时,我们还是从 d p [ i − 1 ] [ j ] dp[i-1][j] dp[i−1][j] 和 d p [ i ] [ j − 1 ] dp[i][j-1] dp[i][j−1] 两个状态转移过来,但是因为增加了字母,我们就增加了 C 或者 D 的长度,所以我们的状态转移就不单是取最值,而是取完最值再减一,而且我们不能减为负数,所以最后的结果还要和 0 取最大值,所以我们 A [ i ] = = B [ j ] A[i]==B[j] A[i]==B[j] 时的转移方程是 d p [ i ] [ j ] = m a x ( 0 , m a x ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) − 1 ) dp[i][j]=max(0,max(dp[i-1][j],dp[i][j-1])-1) dp[i][j]=max(0,max(dp[i−1][j],dp[i][j−1])−1)。最后的答案在所有状态中找最大值即可。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5005;
char s1[maxn],s2[maxn];
int dp[maxn][maxn];
int main()
{
int n,m,ans=0;
scanf("%d %d\n",&n,&m);
scanf("%s",s1+1);
scanf("%s",s2+1);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(s1[i]==s2[j]){
dp[i][j]=dp[i-1][j-1]+2;
}else{
dp[i][j]=max(0,max(dp[i-1][j],dp[i][j-1])-1);
}
ans=max(ans,dp[i][j]);
}
}
printf("%d\n",ans);
return 0;
}