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}
1≤n≤200000,1≤W≤1018,1≤wi≤109
分析
看数据范围不能用传统的背包来做,考虑将
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>W−⌈2W⌉+1≥⌈2W⌉,故若
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)=4⋅LCS(A,B)−∣A∣−∣B∣,其中
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
1≤∣s1∣,∣s2∣≤5000
分析
很明显能看出是一个标准的动态规划,令
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[i−1][j−1]+2,s[i]=s[j]dp[i][j]=max(0,max(dp[i][j−1],dp[i−1][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;
}