做题记录
P1280 尼克的任务
题意:
思路:
很明显这一道dp题目,考虑dp[i]的含义,容易想到表示1~n时间内摸鱼时间的最大值。
接下来考虑转移方程。考虑在时间为i时到达岗位开始工作,即在岗时间为i~n。此时如果有任务,即可考虑从任务结束时间转移过来。不难看出这种方式有一个特点,即逆序循环到第i位时,一定处于任务开始或摸鱼状态,因为任务时往后计算的,不对前面有影响。所以在转移时不用担心转移的位置处于任务中。
转移方程:
如果当前位置没有任务,那么
如果当前位置有任务,那么
代码
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e4+5;
int n, k;
vector<int>v[maxn];
int dp[maxn];
int main(){
scanf("%d%d", &n, &k);
for(int i=1; i<=k; i++){
int p, t;
scanf("%d%d", &p, &t);
v[p].push_back(t);
}
int pos=1;
for(int i=n; i>=1; i--){
if(v[i].size() == 0) dp[i] = dp[i+1] + 1;
else{
for(int j=0; j<v[i].size(); ++j){
dp[i] = max(dp[i], dp[i+v[i][j]]);
}
}
}
printf("%d", dp[1]);
}
P4310 绝世好题
题意
给定长度为
思路
首先想到的是暴力算法:
然后您喜提
然后我们就必须优化一下:(。
接下来便是了
转移方程
若第i个数字第j位为1,
若第i个数字第j位不为1,
代码
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 32;
int f[maxn];
int main(){
int n, mx, ans=mx=0;
scanf("%d", &n);
// for(int i=1; i<=n; i++) scanf("%d", &a[i]);
// for(int i=1; i<=n; i++) f[i]=1;
// for(int i=1; i<=n; i++){
// f[i] = 1
// for(int j=1; j<i; j++){
// if(a[i] & a[j]) f[i] = max(f[i], f[j]+1);
// }
// ans = max(ans, f[i]);
// }
for(int i=1; i<=n; i++){
int x;
scanf("%d", &x);
for(int j=0; j<=31; j++) if((1<<j) & x) mx = max(mx, f[j]+1);
for(int j=0; j<=31; j++) if((1<<j) & x) f[j] = max(mx, f[j]);
ans = max(mx, ans);
}
printf("%d\n", ans);
}
CF1842C Tenzing and Balls
题意
给定n个数字,每次可以选择两个相等的数字,将这两个数字及之间的所有数字删除,求最大删除数字数量。
思路
考虑dp。推理可知如果因两个数字i而删除了n~m位,接下来有出现数字i,此时无视中间的i,就可以删除更大的范围。考虑dp[i][j]含义,即为前i个数字最大删除数字数量,j表示是否删当前数字(0表示不删,1表示删)。为了知道前面是否有与第i位相等的数字和位置,增加lst数组,lst[i]即表示数字大小为i的上一个数。
转移方程
代码
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+5;
int a[maxn], lst[maxn], dp[maxn][2];
void solve(){
int n;
scanf("%d", &n);
for(int i=1; i<=n ;i++) scanf("%d", &a[i]);
for(int i=1; i<=n; i++) lst[i] = 0;
for(int i=1; i<=n; i++){
dp[i][0] = max(dp[i-1][0], dp[i-1][1]);
if(!lst[a[i]]) dp[i][1] = 0;
else dp[i][1] = max(dp[lst[a[i]]][0]+i-lst[a[i]]+1, dp[lst[a[i]]][1]+i-lst[a[i]]);
lst[a[i]] = i;
}
printf("%d\n", max(dp[n][0], dp[n][1]));
}
int main(){
int t;
scanf("%d", &t);
while(t--){
solve();
}
}
CF1798E Multitest Generator
题意
定义test为第一个数字为x的长度为x+1的序列
定义multiset为第一个数字为x,随后由x个test拼接起来的序列
每次修改可以修改某个元素的值。
求对于 1<=i<=n-1,序列a从i开始的后缀变成multiset需要几次修改。
每个询问的修改独立
思路
不难发现答案最大值为2,即将第一个数字修改为1,第二个数字修改为len-2。答案为0时,原本就是x个multitest。答案为1时,第i位后的数已经为完整的多个test,但是test的数量不等于a[i]。考虑逆序循环,dp[i][j]为进行j次修改后,第i位后的test数量。
转移方程
代码
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5+5;
int dp[maxn][2], a[maxn];
void solve(){
int n;
scanf("%d", &n);
for(int i=1; i<=n; i++) scanf("%d", &a[i]), dp[i][0] = dp[i][1] = -1;
dp[n+1][0] = 0, dp[n+1][1] = 0;
int mx = 0;
for(int i=n; i>=1; i--){
if (i + a[i] + 1 <= n + 1) dp[i][1] = dp[i + a[i] + 1][1] + 1;
dp[i][1] = max(dp[i][1], mx + 1);
if (i + a[i] + 1 > n + 1 || dp[i + a[i] + 1][0] == -1) dp[i][0] = -1;
else dp[i][0] = dp[i + a[i] + 1][0] + 1;
mx = max(mx, dp[i][0]);
}
for (int i = 1; i <= n - 1; i++) {
int ans = 2;
if (dp[i + 1][0] == a[i]) ans = 0;
else if (dp[i + 1][0] != -1) ans = 1;
else if (a[i] <= dp[i + 1][1]) ans = 1;
else ans = 2;
cout << ans << " ";
}
cout << endl;
}
int main(){
int x;
scanf("%d", &x);
for(int i=1;i<=x;i++) solve();
}
CF1809F Traveling in Berland
题意
有n个城市围成一圈,第i个能去第i+1个城市,第n个能去第一个城市, 每个城市去下一个城市需要a_i升油。
车的油箱最多能存k升油
每个城市有一个加油站,可以花b[i]块钱加一升油
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】