51nod 1636 教育改革 | DP

51nod 1636 教育改革 | DP

题面

最近A学校正在实施教育改革。
一个学年由n天组成。A学校有m门课程,每天学生必须学习一门课,一门课程必须在一天内学习完。在学习完第i门课程后,学生们会收到 xi 个家庭作业,其中 xi是区间[ai,bi]里的一个整数 。每门课还有一个属性,就是复杂度 ci 。A学校现在要制他们的课程表,具体要求如下:
·在课程表中,随着天数的增加,课程的复杂度是严格递增的。
·除了第1天,每天的作业量必须是前一天的k倍,或者比前一天多k个作业。(假设第i天的作业量为 xi ,则对于i(1<i≤n)到满足 xi = k+xi−1 或 xi = k·xi−1 );
现在,给定天数n,系数k,和m门课程的ai,bi,ci(1≤i≤m)。要求计算一个学年可以安排最大的总作业量( 总作业量的表达式是∑ni=1xi )是多少。

Input
单组测试数据
第一行,三个由空格隔开的整数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。

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

题解

这教育改革怎么越改作业越多2333

dp[i][j][k]表示第i天上j课,当天作业量是k的最大答案
——但是这样显然是不行的因为k太大。
好在虽然k大,k与该课程j作业量的左端点的差不会很大。
那么就让dp[i][j][k]表示第i天上j课,当天作业量是a[j]+k(a的意义如题所述)。然后就可以愉快地转移了!

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
template <class T>
void read(T &x){
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
        if(c == '-') op = 1;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op) x = -x;
}
template <class T>
void write(T x){
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}

const int N = 103, M = 203;
int n, m, K;
ll dp[N][N][M], ans;
struct Lesson {
    int c;
    ll l, r;
    bool operator < (const Lesson b) const{
        return c < b.c;
    }
} a[N];

int main(){

    read(n), read(m), read(K);
    for(int i = 1; i <= m; i++)
        read(a[i].l), read(a[i].r), read(a[i].c);
    sort(a + 1, a + m + 1);
    memset(dp, -1, sizeof(dp));

    for(int j = 1; j <= m; j++)
        for(ll k = a[j].l; k <= a[j].r; k++)
            dp[1][j][k - a[j].l] = k;

    for(int i = 2; i <= n; i++)
        for(int j = 1; j <= m; j++)
            for(ll k = a[j].l; k <= a[j].r; k++)
                for(int h = 1; a[h].c < a[j].c; h++){
                    if(k >= K){
                        ll k1 = k - K;
                        if(k1 >= a[h].l && k1 <= a[h].r && dp[i - 1][h][k1 - a[h].l] != -1)
                            dp[i][j][k - a[j].l] = max(dp[i][j][k - a[j].l], dp[i - 1][h][k1 - a[h].l] + k);
                    }
                    if(k % K == 0){
                        ll k2 = k / K;
                        if(k2 >= a[h].l && k2 <= a[h].r && dp[i - 1][h][k2 - a[h].l] != -1)
                            dp[i][j][k - a[j].l] = max(dp[i][j][k - a[j].l], dp[i - 1][h][k2 - a[h].l] + k);
                    }
                }
    for(int j = 1; j <= m; j++)
        for(ll k = a[j].l; k <= a[j].r; k++)
            ans = max(ans, dp[n][j][k - a[j].l]);
    
    if(ans) puts("YES"), write(ans), putchar('\n');
    else puts("NO");
    
    return 0;
}
posted @ 2017-10-27 14:13  胡小兔  阅读(340)  评论(0编辑  收藏  举报