51nod 1636 教育改革 | DP

时间:2023-03-09 13:31:20
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;
}