当前位置 博文首页 > 文章内容

    P6064 [USACO05JAN]Naptime G

    作者: 栏目:未分类 时间:2020-07-26 16:00:25

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    DP

    最近做了多少道 usaco 了,连 FJ 都认识我了呀

    题意描述

    传送门

    给你 \(N\) 段时间其中 \(B\) 段时间你要用来睡眠,再给你每个时间睡眠可获得的效用值 \(U_i\)

    可惜的是你每次睡眠的第一段时间都要用来入睡(安眠药它不香吗)。

    求你可以获得的最大效用值。

    算法分析

    一眼看上去就是 DP 啊。

    定义 \(f(i,j,1/0)\) 表示:在第 \(i\) 段时间,已近休息了 \(j\) 段时间,此时是否休息。

    假设没有循环时间,那么状态转移方程为:

    \(f(i,j,1)=max(f(i-1,j-1,0),f(i-1,j-1,1)+u_i)\)

    \(f(i,j,0)=max(f(i-1,j,0),f(i-1,j,1))\)

    \(f(i,0,0)=f(1,1,1)=0(1\leq i\leq n),f(i,j,0/1)=-INF(2\leq i,j\leq n)\)

    那么如果没有时间阶段是不断循环的圆这句话这道题就没了。

    那么有的话怎么办办呢?(暗杀良心出题人同志并把这句话删了)

    我的思路是枚举每一段时间为起点,做一次 DP,默默算算时间(\(O(n^3)\))后自闭。

    后来老师说其实只需要两次 DP:

    1. 正常的当时间循环不存在的 DP。
    2. 保证最后一段时间入睡,第一段时间睡着的 DP。(否则时间循环将没有任何意义)

    然后就没了。

    代码实现

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #define N 3831
    using namespace std;
    
    int n,m,a[N],f[N][N][2],ans=0;
    
    int read(){
    	int x=0,f=1;char c=getchar();
    	while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
    	while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
    	return x*f;
    }
    
    int main(){
    	n=read(),m=read();
    	for(int i=1;i<=n;i++) a[i]=read();
    	memset(f,0xcf,sizeof(f));
    	f[1][1][1]=0;
    	for(int i=1;i<=n;i++) f[i][0][0]=0;
    	for(int i=2;i<=n;i++)
    		for(int j=1;j<=m;j++){
    			f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1]);
    			f[i][j][1]=max(f[i-1][j-1][0],f[i-1][j-1][1]+a[i]);
    		}
    	ans=max(f[n][m][0],f[n][m][1]);
    	memset(f,0xcf,sizeof(f));
    	f[1][1][1]=a[1];
    	for(int i=1;i<=n;i++) f[i][0][0]=0;
    	for(int i=2;i<=n;i++)
    		for(int j=1;j<=m;j++){
    			f[i][j][0]=max(f[i-1][j][0],f[i-1][j][1]);
    			f[i][j][1]=max(f[i-1][j-1][0],f[i-1][j-1][1]+a[i]);
    		}
    	ans=max(ans,f[n][m][1]);
    	printf("%d\n",ans);
    	return 0;
    }
    

    完结撒花。