Kuangbin专题12 基础DP
Posted 鱼竿钓鱼干
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kuangbin专题12 基础DP相关的知识,希望对你有一定的参考价值。
Kuangbin专题12 基础DP
讲解视频链接(制作中),如果是板子题目就不讲了
个人觉得有点意思的题目:A,D,K,M,O,Q,S
A - Max Sum Plus Plus
「题意」
你有n个数s1, s2…sn,给你一个整数m,求m个子段和的最大值
「代码」
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+10;
LL s[N],lastmax[N];
LL f[N];
int main(){
int n,m;
while(~scanf("%d%d",&m,&n)){
for(int i=1;i<=n;i++)scanf("%lld",&s[i]);
//f[i][j]=max(f[i][j-1],f[i-1][j-1],f[i-1][j-2],f[i-1][j-3],……f[i-1][i-1]);
memset(f,0,sizeof f);f[0]=-1e9;
memset(lastmax,0,sizeof lastmax);
LL mmax;
for(int i=1;i<=m;i++){//分成i组
mmax=-1e9;
for(int j=i;j<=n;j++){
f[j]=max(f[j-1],lastmax[j-1])+s[j];
lastmax[j-1]=mmax;
mmax=max(mmax,f[j]);
}
}
printf("%lld\\n",mmax);
}
return 0;
}
B - Ignatius and the Princess IV
「题意」
找出现次数最多的数
「代码」
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e6+10;
map<LL,int>mp;
int main(){
int n;
while(~scanf("%d",&n)){
LL ans=0;
mp.clear();
int maxcnt=0;
for(int i=1;i<=n;i++){
LL x;scanf("%lld",&x);
mp[x]++;
if(mp[x]++>maxcnt){
maxcnt=mp[x];
ans=x;
}
}
printf("%lld\\n",ans);
}
return 0;
}
C - Monkey and Banana
「题意」
有n种类型的砖块,每种类型的砖块都有无限个。第i块砖块的长宽高分别用xi,yi,zi来表示。 同时,由于砖块是可以旋转的,每个砖块的3条边可以组成6种不同的长宽高。在构建塔时,当且仅当A砖块的长和宽都分别小于B砖块的长和宽时,A砖块才能放到B砖块的上面,因为必须留有一些空间让猴子来踩。
「代码」
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=5e3+10;
struct cobe{
LL x,y,z;
}c[N];
LL f[N];
int Case;
bool cmp(cobe A,cobe B){
if(A.x!=B.x)return A.x>B.x;
if(A.y!=B.y)return A.y>B.y;
return 0;
}
int main(){
int n;
while(~scanf("%d",&n)&&n){
Case++;
LL ans=0,cnt=0,xx,yy,zz;
for(int i=1;i<=n;i++){
scanf("%lld%lld%lld",&xx,&yy,&zz);
c[cnt+1]={xx,yy,zz};
c[cnt+2]={xx,zz,yy};
c[cnt+3]={yy,xx,zz};
c[cnt+4]={yy,zz,xx};
c[cnt+5]={zz,xx,yy};
c[cnt+6]={zz,yy,xx};
cnt+=6;
}
sort(c+1,c+1+cnt,cmp);
for(int i=1;i<=cnt;i++)f[i]=c[i].z;
for(int i=1;i<=cnt;i++){
for(int j=1;j<i;j++){
if(c[i].x<c[j].x&&c[i].y<c[j].y){
f[i]=max(f[i],f[j]+c[i].z);
}
}
ans=max(ans,f[i]);
}
printf("Case %d: maximum height = %lld\\n",Case,ans);
}
return 0;
}
D - Doing Homework
「题意」
有 n 个作业,完成某个作业需要一定的时间,而且每个作业有一个截止时间,若超过截止时间,一天就要扣一分。如何安排做作业,使得扣的分数最少。
Tips: 如果开始做某个作业,就必须把这个作业做完了,才能做下一个作业。
数据范围15,状态压缩DP
「代码」
/*参考https://blog.csdn.net/qq_46276931/article/details/116567454*/
#include<bits/stdc++.h>
using namespace std;
const int N=16;
int f[1<<N],v[1<<N],last[1<<N];
char name[N][105];
int d[N],c[N];
void print(int x){
if(!x)return;
print(x-(1<<last[x]));
cout<<name[last[x]]<<endl;
}
int main(){
int T;
cin>>T;
while(T--){
int n;
cin>>n;
for(int i=0;i<n;i++)cin>>name[i]>>d[i]>>c[i];
int siz=1<<n;
for(int i=1;i<=siz-1;i++){
f[i]=1e9+7;
for(int j=n-1;j>=0;j--){
int k = 1 << j;
if (!(i & k)) continue;
int w = v[i - k] + c[j] - d[j];//算转移过来超出的时间
if (w < 0) w = 0;//截止前完成了
if (f[i] > f[i - k] + w) {
f[i] = f[i - k] + w;//更新最小值
v[i] = v[i - k] + c[j];//记录第几天了
last[i] = j;//记录前一个状态
}
}
}
cout<<f[siz-1]<<endl;
print(siz-1);
}
return 0;
}
E - Super Jumping! Jumping! Jumping!
「题意」
求最大上升子序列和
「代码」
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e3+10;
LL f[N],a[N];
int main(){
int n;
while(~scanf("%d",&n)&n){
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
f[i]=a[i];
}
LL ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
if(a[j]<a[i])f[i]=max(f[i],f[j]+a[i]);
}
}
for(int i=1;i<=n;i++)ans=max(ans,f[i]);
printf("%lld\\n",ans);
}
return 0;
}
F - Piggy-Bank
「题意」
完全背包,求体积恰好为m的物品组合的最小价值
「代码」
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=510,M=10005;
int w[N],v[N];
int f[N][M];
int main(){
int T;
scanf("%d",&T);
while(T--){
int E,F,n,m;scanf("%d%d%d",&E,&F,&n);
for(int i=1;i<=n;i++)scanf("%d%d",&v[i],&w[i]);
m=F-E;
memset(f,0x3f,sizeof f);
for(int i=0;i<=n;i++)f[i][0]=0;//从0开始
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
f[i][j]=f[i-1][j];
if(j>=w[i])f[i][j]=min(f[i][j],f[i][j-w[i]]+v[i]);
}
}
if(f[n][m]!=0x3f3f3f3f)printf("The minimum amount of money in the piggy-bank is %lld.\\n",f[n][m]);
else puts("This is impossible.");
}
}
G - 免费馅饼
「题意」
馅饼从天掉,降落范围[0,10]。小王开始站在位置5,每次最大水平移动距离为1。问在最多能接到多少硬币,背包容量不限,同一位置同一时间可能有多个馅饼。
走地图DP
「代码」
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
LL g[N][11],f[N][11];
int Tmax;
LL dfs(int t,int pos){
LL tmp=0;
if(t>Tmax)return 0;
if(f[t][pos])return f[t][pos];
tmp=max(tmp,dfs(t+1,pos));
if(pos-1>=0)tmp=max(tmp,dfs(t+1,pos-1));
if(pos+1<=10)tmp=max(tmp,dfs(t+1,pos+1));
return f[t][pos]=tmp+g[t][pos];
}
int main(){
int n;
while(~scanf("%d",&n)&&n){
memset(g,0,sizeof g);
memset(f,0,sizeof f);
Tmax=0;
for(int i=1;i<=n;i++){
int x,T;scanf("%d%d",&x,&T);
g[T][x]++;
Tmax=max(Tmax,T);
}
LL ans=dfs(0,5);
printf("%lld\\n",ans);
}
return 0;
}
H - Tickets
「题意」
现在有n个人要买电影票,如果知道每个人单独买票花费的时间,还有和前一个人一起买花费的时间,问最少花多长时间可以全部买完票。
状态机DP
「代码」
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e3+10;
int single_time[N],merge_time[N],value[N];
int f[N][2];
int main(){
int n;
while(~scanf("%d",&n)){
while(n--){
memset(f,0,sizeof f);
int k;scanf("%d",&k);
int all_time=0;
for(int i=1;i<=k「kuangbin带你飞」专题十二 基础DP
算法系列学习状压dp [kuangbin带你飞]专题十二 基础DP1 D - Doing Homework
算法系列学习[kuangbin带你飞]专题十二 基础DP1 G - 免费馅饼