1636 教育改革(dp,背包变形~变得有点大,三维)

题目描述:

1636 教育改革

最近A学校正在实施教育改革。

一个学年由n天组成。A学校有m门课程,每天学生必须学习一门课,一门课程必须在一天内

学习完。在学习完第i门课程后,学生们会收到 xixi 个家庭作业,其中 xi是区间[ai,bi]里的一个

整数xi是区间[ai,bi]里的一个整数 。每门课还有一个属性,就是复杂度 cici 。A学校现在要制他

们的课程表,具体要求如下:

在课程表中,随着天数的增加,课程的复杂度是严格递增的。

除了第1天,每天的作业量必须是前一天的k倍,或者比前一天多k个作业。(假设第i天的作业

量为 xixi ,则对于i(1<i≤n)到满足 xi = k+xi−1xi = k+xi−1 或 xi = k⋅xi−1xi = k·xi−1 );

现在,给定天数n,系数k,和m门课程的ai,bi,ci(1≤i≤m)。要求计算一个学年可以安排最

大的总作业量( 总作业量的表达式是∑ni=1xi总作业量的表达式是∑i=1nxi )是多少。

 收起

输入

单组测试数据
第一行,三个由空格隔开的整数n,m,k(1≤n≤m≤50,1≤k≤100),表示一个学年的天数,课程的数量,
和作业增量系数。
接下来的m行,
每行有三个整数,ai,bi,ci(1≤ai≤bi≤10^16,bi-ai≤100,1≤ci≤100)
分别表示第i门课程的最小作业量,和最多作业量,以及复杂度。
不同的课程可以有相同的复杂度。课程编号从1到m。

输出

如果有可行方案,第一行输出“YES”(没有引号),第二行输出最大的作业量。
如果没有可行方案,则输出一行“NO”(没有引号)。

输入样例

4 5 2
1 10 1
1 10 2
1 10 3
1 20 4
1 100 5

输出样例

YES
78

思路:

状态描述:

       dp【i】【j】【k】:将第 i 门课程安排在第 j 天,布置K+arr[i].a的作业量

时前 j 天获得的最大最大作业量。

递推关系:

        dp[i][j][k]=max(dp[i][j][k],dp[c值比c[i] 小的课程号][j-1][k减去/除以相对限制])

PS:第一天的特判、k-相应限制能否与目标课程适应、数组下标负数的防止、要求难度严格单增。

目标状态:

     dp【i】【n】【k】。

代码实现:

//关键代码
if(arr[i].c!=arr[l].c&&arr[i].a+k-kn>=arr[l].a&&
  arr[i].a+k-kn<=arr[l].b&&dp[l][j-1][arr[i].a+k-kn-arr[l].a])
    dp[i][j][k]=max(dp[i][j][k],dp[l][j-1][arr[i].a+k-kn-arr[l].a]+arr[i].a+k);
if(arr[i].c!=arr[l].c&&(arr[i].a+k)/kn>=arr[l].a&&
  (arr[i].a+k)/kn<=arr[l].b&&dp[l][j-1][(arr[i].a+k)/kn-arr[l].a])
    dp[i][j][k]=max(dp[i][j][k],dp[l][j-1][(arr[i].a+k)/kn-arr[l].a]+k+arr[i].a);
#include<iostream>
#include<cstring>
#include<cmath>
#include<stack>
#include<algorithm>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
const int N=4*2e5+100;
struct Node {
    LL a,b,c;
} arr[N];
bool cmp1(Node aa,Node bb) {
    return aa.c<bb.c;
}
LL dp[52][52][102];
int main() {
    int n,m,kn;
    LL ans;
    while(cin>>n>>m>>kn) {
        ans=0;
        memset(dp,0,sizeof(dp));
        for(int i=1; i<=m; i++) {
            cin>>arr[i].a>>arr[i].b>>arr[i].c;
        }
        sort(arr+1,arr+1+m,cmp1);
        for(int i=1; i<=m; i++)
            for(int j=1; j<=n; j++)
                for(int k=0; k<=arr[i].b-arr[i].a; k++) {
                    if(j==1) {
                        dp[i][j][k]=arr[i].a+k;
                    } else {
                        for(int l=1; l<i; l++) {
                            //这个 if 的 条件很关键
                            if(arr[i].c!=arr[l].c&&arr[i].a+k-kn>=arr[l].a&&
                            arr[i].a+k-kn<=arr[l].b&&dp[l][j-1][arr[i].a+k-kn-arr[l].a]) {
                            dp[i][j][k]=max(dp[i][j][k],
                            dp[l][j-1][arr[i].a+k-kn-arr[l].a]+arr[i].a+k);
                            }
                        }
                    }
                    if((arr[i].a+k)%kn==0) {
                        for(int l=1; l<i; l++) {
                            //这个 if 的 条件很关键
                            if(arr[i].c!=arr[l].c&&(arr[i].a+k)/kn>=arr[l].a&&
                            (arr[i].a+k)/kn<=arr[l].b&&dp[l][j-1][(arr[i].a+k)/kn-arr[l].a]) {
                            dp[i][j][k]=max(dp[i][j][k],
                            dp[l][j-1][(arr[i].a+k)/kn-arr[l].a]+k+arr[i].a);
                            }
                        }
                    }
                }
        for(int i=1; i<=m; i++) {
            for(int j=0; j<=arr[i].b-arr[i].a; j++) {
                ans=max(ans,dp[i][n][j]);
            }
        }
        if(ans) {
            cout<<"YES"<<endl;
            cout<<ans<<endl;
        } else {
            cout<<"NO"<<endl;
        }
    }
    return 0;

}

THE END;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值