Vj程序设计作业H11

A : 爬台阶

题目描述

楼上有 n 级台阶,其中有 m 级台阶是不安全的。yhf 一开始站在第 0 级台阶上,希望最终走到第 n 级台阶

yhf 跨一步满足以下约束:

  • 只能向前走
  • 不能落脚在不安全的台阶上
  • 最多迈 k 级台阶
  • 落脚点不能超过第 n 级台阶

也就是说,若某一刻 yhf 站在第 c 级台阶上,那么他下一步可以落脚的位置 x 满足 c<x≤min(c+k,n) 且第 x 级台阶是安全的。那么,yhf 有多少种方法走到第 n 级台阶

输入格式

第一行三个整数 n,m,k ,描述见上文

第二行 m 个整数,d1​,d2​,...,dm​ ,其中 1≤di​<n ,表示不安全台阶的编号

输出格式

一个整数,模 998244353 后的方案数

测试样例

样例输入

5 1 2
3

样例输出

2

数据规模

对于 100% 的数据,1≤m<n≤106,1≤k≤106

解答

#include<bits/stdc++.h>
using namespace std;
int n,m,k;
const long long p=998244353;
const int maxn=1e6+6;
long long sum[maxn],f[maxn];// 前缀和,动态规划数组

void init(){
    for (int i = 0; i <= n;i++){
        f[i] = 0;
        // sum[i] = 0;
    }
}
int main(){
    // memset(f,0,sizeof(f));
    
    cin>>n>>m>>k;
    init();
    int d;
    while(m--){
        cin>>d;
        f[d]=-1;
    }
    f[0]=1;
    sum[0]=1;
    for(int i=1;i<=k;i++){
        if(f[i]!=-1){
            f[i]=sum[i-1]%p;
            sum[i]=(sum[i-1]+f[i]);
            // sum[i]=sum[i]%p;
        }
        else    
            sum[i]=sum[i-1];
    }
    for(int i=k+1;i<=n;i++){
        if(f[i]==-1){
            sum[i]=sum[i-1];
        }
        else{
            f[i]=(sum[i-1]-sum[i-k-1])%p;
            sum[i]=(sum[i-1]+f[i]);
            // sum[i]=sum[i]%p;
        }
    }
    cout<<f[n]<<endl;
    // system("pause");
    return 0;
}

B : 拿数问题

题目描述

给定 n 个数,我们要从中选出多若干个数,其中任意大小不同的两数差的绝对值不能为 1,那么选出的数之和最大是多少。

输入格式

第一行一个整数 n 。

第二行 n 个整数,a1​,a2​,...,an​ ,表示这 n 个数

输出格式

一个整数,选出的数的和的最大值

测试样例

样例输入

5
1 1 3 2 3

样例输出

8

数据规模

对于 100% 的数据,1≤n≤106,1≤ai​≤106

解答

#include <bits/stdc++.h>

using namespace std;
#define ll long long

ll n;
ll a[1000001];
ll b[1000001];
ll dp[1000001];
void init(){
    for (int i = 0; i <= n;i++){
        a[i] = 0;
        b[i] = 0;
        dp[i] = 0;
    }
}



int main(){
    cin >> n;
    init();
    for (int i = 1; i <= n;i++){
        cin >> a[i];
        b[a[i]]++;
    }
    for (int i = 1; i <= 1e6;i++){
        if(i==1){
            dp[i] = dp[0] + i * b[i];
        }else{
            dp[i] = max(dp[i - 1], dp[i - 2] + i * b[i]);
        }   
    }
    cout << dp[1000000] << endl;
    return 0;
}

C : 矩阵选数

题目描述

给定一个 3 行,n 列的矩阵,我们要在矩阵的每一列选一个数。对于第 i(1≤i≤n) 列,我们令 di​ 为第 i 列选择的数。那么,∑1n−1​∣di​−di+1​∣ 最小是多少

输入格式

第一行一个整数 n ,描述见上文

后面三行每行 n 个整数,为矩阵的各个元素

输出格式

一个整数,题目要求的最小值

测试样例

样例输入

5
5 10 5 4 4
1 7 8 4 0
3 4 9 0 3

样例输出

3

数据规模

对于 100% 的数据,1≤n≤106 ,矩阵中数据绝对值不超过 106

解答

// #include <bits/stdc++.h>
#include<bits/stdc++.h>
using namespace std;
#define ll long long

ll n;
ll a[3][1000001];
ll dp[1000001][3];

void init(){
    for (int i = 0; i <= 2;i++){
        for (int j = 0; j <= n;j++){
            a[i][j] = 0;
            dp[j][i] = 0;
        }
    }
}
int main(){
    cin >> n;
    init();
    for (int i = 0; i < 3;i++){
        for (int j = 1; j <= n;j++){
            cin >> a[i][j];
        }
    }
    dp[1][0] = 0;
    dp[1][1] = 0;
    dp[1][2] = 0;
    for (int i = 2; i <= n;i++){
        dp[i][0] = min(min(dp[i - 1][0] + abs(a[0][i] - a[0][i - 1]), dp[i - 1][1] + abs(a[0][i] - a[1][i - 1])), dp[i - 1][2] + abs(a[0][i] - a[2][i - 1]));
        dp[i][1] = min(min(dp[i - 1][0] + abs(a[1][i] - a[0][i - 1]), dp[i - 1][1] + abs(a[1][i] - a[1][i - 1])), dp[i - 1][2] + abs(a[1][i] - a[2][i - 1]));
        dp[i][2] = min(min(dp[i - 1][0] + abs(a[2][i] - a[0][i - 1]), dp[i - 1][1] + abs(a[2][i] - a[1][i - 1])), dp[i - 1][2] + abs(a[2][i] - a[2][i - 1]));
    }
    cout << min(dp[n][0], min(dp[n][1], dp[n][2])) << endl;
    return 0;
}

D : 最长上升子序列

题目描述

对于一个整数序列 A=(a1​,a2​,…,ak​),定义 A 的子序列为:从 A 中删除若干个元素后(允许不删,也允许将所有 k 个元素都删除),剩下的元素按照原来的顺序所组成的序列。如果这个子序列的元素从左到右严格递增,则称它为 A 的一个上升子序列。其中包含元素数量最多的上升子序列称为 A 的最长上升子序列。例如,(2,4,5,6) 和 (1,4,5,6) 都是 (2,1,1,4,7,5,6) 的最长上升子序列,长度都为 4。

那么,给定一个序列 A=(a1​,a2​,…,an​), 求 A 的最长上升子序列的长度

输入格式

第一行一个整数 n ,代表序列 A 的长度

第二行是 n 个由空格隔开的整数,代表 a1​,a2​,…,an​

输出格式

一个整数,代表最长上升子序列的长度

测试样例

样例输入

7
2 1 1 4 7 5 6

样例输出

4

数据规模

对于 100% 的数据,1≤n≤106,1≤ai​≤106

解答

#include <bits/stdc++.h>

using namespace std;
const int MAXN = 1e6;
int a[MAXN + 10];
int BIT[MAXN + 10];
int f[MAXN + 10];
int lowbit(int x){
    return x & -x;
}

void update(int x,int val){
    while(x<=MAXN){
        BIT[x] = max(BIT[x], val);
        x += lowbit(x);

    }
}


int query(int x){
    int res = 0;
    while(x){
        res = max(res, BIT[x]);
        x -= lowbit(x);
    }
    return res;
}

int main(){
    int n;
    cin >> n;
    for (int i = 1; i <= n;i++){
        cin >> a[i];
    }
    int ans = 0;
    for (int i = 1; i <= n;i++){
        f[i] = query(a[i] - 1) + 1;
        update(a[i], f[i]);
        ans = max(ans, f[i]);
    }
    cout << ans << endl;
    return 0;
}

E : 最长公共子序列

题目描述

给定序列 A=(a1​,a2​,…,an​) 和 B=(b1​,b2​,…,bm​) ,求它们的最长公共子序列

子序列的定义参考题目 最长上升子序列

输入格式

第一行两个整数 n,m 代表序列 A,B 的长度

第二行是 n 个由空格隔开的整数,代表 a1​,a2​,…,an​

第三行是 m 个由空格隔开的整数,代表 b1​,b2​,…,bm​

输出格式

输出一个整数,代表最长公共子序列的长度

测试样例

样例输入

5 5
3 2 1 4 5
1 2 3 4 5

样例输出

3

数据规模

对于 100% 的数据,1≤n,m≤5000,1≤ai​,bi​≤104

解答

#include <bits/stdc++.h>

using namespace std;
#define ll long long

ll f[5001][5001];
ll a[100001], b[100001];
ll n, m;
void init(){
    for (int i = 0; i <= n;i++){
        a[i] = 0;
    }
    for (int i = 0; i <= m;i++){
        b[i] = 0;
    }
    for (int i = 0; i <= n;i++){
        for (int j = 0; j <= m;j++){
            f[i][j] = 0;
        }
    }
}

void ff(){
    for (int i = 1; i <= n;i++){
        for (int j = 1; j <= m;j++){
            if(a[i]==b[j]){
                f[i][j] = f[i - 1][j - 1] + 1;
            }else{
                f[i][j] = max(f[i - 1][j], f[i][j - 1]);
            }
        }
    }
}

int main(){
    cin >> n>>m;
    init();
    for (int i = 1; i <= n;i++){
        cin >> a[i];
    }
    for (int i = 1; i <= m;i++){
        cin >> b[i];
    }
    ff();
    cout << f[n][m] << endl;
    return 0;
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值