Acwing——第 89 场周赛

题目链接

4803. 满足的数 简单
4804. 构造矩阵 中等
4805. 加减乘 困难

题目描述

4803. 满足的数

给定 n个不超过 5 的正整数 a1,a2,…,an

不妨设 S=a1+a2+…+an

请你统计,一共有多少个不同的整数 x 能够同时满足以下所有条件:

  • 1 ≤ x ≤ 5 1≤x≤5 1x5
  • ( 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 1n100
  • 1 ≤ a i ≤ 5 1≤a_i≤5 1ai5
输入样例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 1m,列编号为 1 ∼ n 1∼n 1n

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 1m,n100
输入样例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 1n1071x,y109
输入样例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(i1)+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(i1)=min(f(i1),f(i)+x) (因为 f ( i − 1 ) f(i-1) f(i1) 可能还会由 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;
    
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值