题目链接
4803. 满足的数 简单
4804. 构造矩阵 中等
4805. 加减乘 困难
题目描述
4803. 满足的数
给定 n
个不超过 5 的正整数 a1,a2,…,an
。
不妨设 S=a1+a2+…+an
。
请你统计,一共有多少个不同的整数 x 能够同时满足以下所有条件:
- 1 ≤ x ≤ 5 1≤x≤5 1≤x≤5
-
(
S
+
x
)
m
o
d
(
n
+
1
)
≠
1
(S+x)mod(n+1)≠1
(S+x)mod(n+1)=1输入格式第一行包含整数
n
。
输入格式
第一行包含整数 n
。
第二行包含 n
个正整数 a1,a2,…,an
。
输出格式
一个整数,表示满足条件的 x
的数量。
数据范围
- 1 ≤ n ≤ 100 1≤n≤100 1≤n≤100
- 1 ≤ a i ≤ 5 1≤a_i≤5 1≤ai≤5
输入样例1:
1
1
输出样例1:
3
输入样例2:
1
2
输出样例2:
2
输入样例3:
2
3 5
输出样例3:
3
时间复杂度: O ( n ) O(n) O(n)
代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 110;
int a[N];
int main(){
int n;
cin>>n;
int sum = 0;
for(int i = 1;i <= n;i++){
cin>>a[i];
sum += a[i];
}
int ans = 0;
for(int x = 1;x <= 5;x++){
if((sum + x) % (n + 1) != 1) ans++;
}
cout<<ans<<endl;
return 0;
}
4804. 构造矩阵
给定一个
m
m
m行
n
n
n 列的 01
矩阵 B。
请你构造一个
m
m
m 行
n
n
n 列的 01
矩阵 A。
矩阵的行编号为 1 ∼ m 1∼m 1∼m,列编号为 1 ∼ n 1∼n 1∼n。
B i j B_{ij} Bij 表示矩阵 B 中第 i 行第 j 列的元素。
要求,构造的矩阵 A 满足,对于每一个 B i j B_{ij} Bij:
-
如果 B i j = 0 B_{ij}=0 Bij=0,则矩阵 A 中第 i 行的 n n n 个元素以及第 j 列的 m m m 个元素总共 n + m n+m n+m 个元素必须全都为 0。
-
如果 B i j = 1 B_{ij}=1 Bij=1,则矩阵 A 中第 i 行的 n n n 个元素以及第 j 列的 m m m 个元素总共 n + m n+m n+m 个元素不能全都为 0。
输入格式
第一行包含两个整数 m , n m,n m,n。
接下来 m m m 行,每行包含 n n n 个整数 0 或 1,其中第 i 行第 j 列的整数表示 B i j B_{ij} Bij。
输出格式
如果不存在满足条件的矩阵 A,则输出一行 NO
即可。
否则,第一行输出 YES
,接下来
m
m
m 行,每行输出
n
n
n个整数,用来表示矩阵 A。
如果答案不唯一,则输出任意合理答案均可。
数据范围
- 1 ≤ m , n ≤ 100 1≤m,n≤100 1≤m,n≤100
输入样例1:
2 2
1 0
0 0
输出样例1:
NO
输入样例2:
2 3
1 1 1
1 1 1
输出样例2:
YES
1 1 1
1 1 1
输入样例3:
2 3
0 1 0
1 1 1
输出样例3:
YES
0 0 0
0 1 0
分析:
我们先将整个数组初始化为全部是 1
,我们直接先处理所有
B
i
j
=
0
B_{ij} = 0
Bij=0 的情况,将对应的行和列全部置为0。
接着我们再处理
B
i
j
=
1
B_{ij} = 1
Bij=1 的情况,对于其对应行 和 列的元素之和 如果等于0,就直接打印 NO
返回;否则最后打印 YES
,再打印数组
时间复杂度: O ( n 2 ) O(n^2) O(n2)
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 110;
int n,m;
int a[N][N],b[N][N];
//对应行 和 列都更新为0
void update(int x,int y){
for(int j = 1;j <= n;j++) b[x][j] = 0;
for(int i = 1;i <= m;i++) b[i][y] = 0;
}
//获取对应行 和 列的元素之和
int getsum(int x,int y){
int sum = 0;
for(int j = 1;j <= n;j++) sum += b[x][j];
for(int i = 1;i <= m;i++) sum += b[i][y];
//因为 + 了两次 b[x][y],所以要减一次
return sum - b[x][y];
}
int main(){
cin>>m>>n;
for(int i = 1;i <= m;i++){
for(int j = 1;j <= n;j++) {
cin>>a[i][j];
b[i][j] = 1;
}
}
for(int i = 1;i <= m;i++){
for(int j = 1;j <= n;j++){
if(!a[i][j]) update(i,j);
}
}
for(int i = 1;i <= m;i++){
for(int j = 1;j <= n;j++){
if(a[i][j]){
int sum = getsum(i,j);
if(sum == 0){
puts("NO");
return 0;
}
}
}
}
puts("YES");
for(int i = 1;i <= m;i++){
for(int j = 1;j <= n;j++){
cout<<b[i][j]<<" ";
}
puts("");
}
return 0;
}
4805. 加减乘
规定两种数字操作:
- 加减操作,将数字加 1 或减 1,代价为
x
。 - 乘法操作,将数字乘 2,代价为
y
。
每种操作的使用次数不限。
请你计算,通过上述操作,将 0 变为 n,所需花费的最小代价。
输入格式
共一行,包含三个整数 n , x , y n,x,y n,x,y。
输出格式
一个整数,表示最小代价。
数据范围
- 1 ≤ n ≤ 1 0 7 , 1 ≤ x , y ≤ 1 0 9 1≤n≤10^7,1≤x,y≤10^9 1≤n≤107,1≤x,y≤109
输入样例1:
8 1 1
输出样例1:
4
输入样例2:
2 3
1 1 1
1 1 1
输出样例2:
8 1 10
输入样例3:
8
分析:
本题使用 动态规划 求解。我们定义
f
(
i
)
f(i)
f(i) 是从 0 ~ n
的最小代价。
状态转移:
- f ( i ) = f ( i − 1 ) + x f(i) = f(i-1) + x f(i)=f(i−1)+x
- 当
i
是偶数时, f ( i ) = m i n ( f ( i ) , f ( i / 2 ) + y ) f(i) = min( f(i) , f(i/2) + y ) f(i)=min(f(i),f(i/2)+y) - f ( i − 1 ) = m i n ( f ( i − 1 ) , f ( i ) + x ) f(i-1) = min( f(i - 1) , f(i) + x) f(i−1)=min(f(i−1),f(i)+x) (因为 f ( i − 1 ) f(i-1) f(i−1) 可能还会由 f ( i ) f(i) f(i) 更新而来,所以要等 f ( i ) f(i) f(i) 先更新完毕)
时间复杂度: O ( n ) O(n) O(n)
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
using LL = long long;
int n,x,y;
const int N = 1e7+10;
//用 long long 防止溢出
LL f[N];
int main(){
cin>>n>>x>>y;
memset(f,0,sizeof f);
//之所以是 1 ~ n + 1 ,是因为当 i = n 时,f[n] 还可能会由 f[n+1] + x 更新而来
for(int i = 1;i <= n+1;i++){
f[i] = f[i-1] + x;
if(i % 2 == 0) f[i] = min(f[i],f[i/2] + y);
f[i-1] = min(f[i-1],f[i] + x);
}
cout<<f[n]<<endl;
return 0;
}