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;
}