
A P1802 5 倍经验日
赛时代码
cpp
#include<bits/stdc++.h>
using namespace std;
long long dp[1005];
int main(){
int n,x;
cin>>n>>x;
for(int i=1;i<=n;i++){
int l,w,u;
cin>>l>>w>>u;
for(int j=x;j>=1;j--){//没有枚举到0
dp[j]=max(dp[j],dp[j]+l);
if(j>=u){
dp[j]=max(dp[j],dp[j-u]+w);
}
}
}
cout<<dp[x]*5;
return 0;
}
改后代码
cpp
#include<bits/stdc++.h>
using namespace std;
long long dp[1005];
int main(){
int n,x;
cin>>n>>x;
for(int i=1;i<=n;i++){
int l,w,u;
cin>>l>>w>>u;
for(int j=x;j>=0;j--){
if(j>=u){
dp[j]=max(dp[j]+l,dp[j-u]+w);
}else{
dp[j]+=l;
}
}
}
cout<<dp[x]*5;
return 0;
}
挂了70分。
B B4177 [BCSP-X 2024 6 月初中组] 尽量接近
赛时代码
cpp
#include<bits/stdc++.h>
using namespace std;
bool dp[1000005];
int main(){
dp[0]=1;
int n,k,sum=0;
cin>>n>>k;
for(int i=1;i<=n;i++){
int x;
cin>>x;
sum+=x;
for(int j=sum;j>=x;j--){
dp[j]|=dp[j-x];
}
}
int mn=INT_MAX;
bool cc=0;
for(int i=k*2;i>=0;i--){
if(dp[i]){
if(abs(k-i)<mn){
mn=abs(k-i);
if(i>k){
cc=1;
}
}
}
}
if(cc){
cout<<mn+k;
}else{
cout<<mn-k;
}
return 0;
}
本来用的精卫填海的思路,后来发现写错了,于是就仿照kkksc03临时抱佛脚来写,于是A了。
改后代码
cpp
#include<bits/stdc++.h>
using namespace std;//隐藏了两位巨佬的名字
int a[55];
int dp[1000005],n,k,sum=0;
int ggy(int lyz){//因为两次背包,所以用函数包装
memset(dp,0,sizeof dp);
for(int i=1;i<=n;i++){//01背包
for(int j=lyz;j>=a[i];j--){//枚举背包容量
dp[j]=max(dp[j],dp[j-a[i]]+a[i]);
}
}
return dp[lyz];
}
int main(){
dp[0]=1;
cin>>n>>k;
for(int i=1;i<=n;i++){
int x;
cin>>a[i];
sum+=a[i];
}
if(sum<=k){
cout<<sum;
return 0;
}
int x1=ggy(k);//容量为k
int x2=sum-ggy(sum-k);//容量为sum-k,最后答案要用sum减去
if(k-x1<=x2-k){//如果第一个答案比第一个答案跟接近k,相同时选更小的
cout<<x1;
}else{
cout<<x2;
}
return 0;
}
挂了80分。
C P13015 [GESP202506 六级] 学习小组
为什么有一个人没有A呢,好 难 猜 啊 ~
cpp
#include<bits/stdc++.h>
using namespace std;
int a[1005],dp[1005];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){//枚举物品,重量为i,价值为a[i]
for(int j=i;j<=n;j++){//完全背包
dp[j]=max(dp[j],dp[j-i]+a[i]);
}
}
cout<<dp[n];
return 0;
}
D P8816 [CSP-J 2022] 上升点列
40分是骗的,不要以为我想到了正解......
骗分代码
cpp
#include<bits/stdc++.h>
using namespace std;
struct node{
int x,y;
}a[505];
bool cmp(node x,node y){
if(x.x==y.x){
return x.y<y.y;
}
return x.x<y.x;
}
int dp[505];
bool check(int x,int y){
if(a[x].x==a[y].x&&a[x].y+1==a[y].y)return 1;
if(a[x].x+1==a[y].x&&a[x].y==a[y].y)return 1;
return 0;
}
int main(){
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].y;
}
sort(a+1,a+1+n,cmp);
int mx=0;
for(int i=1;i<=n;i++){
dp[i]=1;
for(int j=1;j<i;j++){
if(check(j,i)){
dp[i]=max(dp[i],dp[j]+1);
}
}
mx=max(mx,dp[i]);
}
cout<<mx;
return 0;
}
杨老师的原话:"这道题没有人能拿到"然后顿了一下,"40分以上。"
题意:给定n个点,允许添加k个点,使得所有点的x和y都是正整数,且选出的点的序列构成一条最长的折线,x和y单调不减。
因为序列中相邻两点的关系只有两种,要么在下面,要么在左边,所以对于点 i 和点 j ,中间需要添加的点数=max(0,|a[i].x-a[j].x|+|a[i].y-a[j].y|)。
状态:dp[i][j]表示以第 i 个点为结尾已经添加 j 个点的最大长度。
答案:max(dp[i][k])
初始状态:dp[i][j]=j+1
cpp
#include<bits/stdc++.h>
using namespace std;
struct node{
int x,y;
}a[505];
bool cmp(node x,node y){
if(x.x==y.x){
return x.y<y.y;
}
return x.x<y.x;
}
int dp[505][505];
int check(int x,int y){//计算这两点之间最少要加几个点才能相连
if(x==y)return 0;//同一点返回0就行了
return abs(a[x].x-a[y].x)+abs(a[x].y-a[y].y)-1;
}
int main(){
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i].x>>a[i].y;
}
sort(a+1,a+1+n,cmp);//这里提到了排序,说明DP和贪心息息相关
for(int i=1;i<=n;i++){
for(int j=0;j<=k;j++){
dp[i][j]=j+1;//加j个点再算上i点,就是j+1个点
}
}
for(int i=1;i<=n;i++){
for(int j=0;j<=k;j++){
for(int p=1;p<=i;p++){
if(p==i){
dp[i][j]=max(dp[i][j],dp[p][j-1]+1);
}
int x=check(i,p);
if(p<i&&x<=j&&a[p].y<=a[i].y){
dp[i][j]=max(dp[i][j],dp[p][j-x]+x+1);
}
}
}
}
int ans=0;
for(int i=1;i<=n;i++){
ans=max(ans,dp[i][k]);
}
cout<<ans;
return 0;
}