最近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 )是多少。
单组测试数据 第一行,三个由空格隔开的整数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
题解:动态规划一般步骤:分解子问题,得到转移方程。在本题中,首先按照复杂度c进行升序排序。对于i位置,我们定义dp[i]为0 ~ i - 1能到达i位置的容器(即满足p[i] > p[j] && j位置有元素 + k或者*k后范围在p[i].b ~ p[i].b之间)很明显i是能到达i的(即以i位置的左右区间元素为开始元素)对于能满足+k或者*k在p[i].a ~ p[i].b区间的元素,将新元素加入容器中,并且更新dp[i]的num值(+1)。当num值等于n时,表示能够满足n天的课程,将ok变成1(ok初始为0,最终为0则是NO,反之为YES)
接下来的问题是怎么获得最大值,我们发现,当num等于n时,当前放入容器的新元素的最大值是不受任何约束的(即它取最大值不受之前范围的影响),而在它取最大值时,约束了num等于n - 1时的取值范围,在范围内去任何元素都是不受约束的,基于此我们从最大值开始逆推,当当前维护的最大值元素 - k1 或者 /k1在num - 1 元素的范围内时,取较大值,反之,哪个不符合取另外一个(不可能两个都不符合)
AC代码
#include <stdio.h>
#include <iostream>
#include <string>
#include <queue>
#include <map>
#include <vector>
#include <algorithm>
#include <string.h>
#include <cmath>
using namespace std;
typedef long long ll;
const int maxn = 111;
struct node{
ll a, b, c;
}p[maxn];
struct node1{
ll num, prex, prey;
node1(ll num_, ll x_, ll y_):num(num_), prex(x_), prey(y_){}
};
vector<node1> dp[maxn];
vector<ll> a[maxn][10 * maxn];
bool cmp(node a1, node a2){
return a1.c < a2.c;
}
bool check(ll l, ll r, ll a, ll b){
if(a > r || b < l)
return false;
return true;
}
int main(){
// freopen("in.txt", "r", stdin);
ll n, m, k1;
scanf("%lld%lld%lld", &n, &m, &k1);
for(ll i = 0; i < m; i++)
scanf("%lld%lld%lld", &p[i].a, &p[i].b, &p[i].c);
sort(p, p + m, cmp);
ll ok = 0;
ll ans = 0;
if(n == 1){
for(ll i = 0; i < m; i++)
ans = max(ans, p[i].b);
printf("YES\n");
printf("%lld\n", ans);
return 0;
}
for(ll i = 0; i < m; i++){
if(m - i >= n){
dp[i].push_back(node1(1, -1, -1));
for(ll j = p[i].a; j <= p[i].b; j++)
a[i][0].push_back(j);
}
for(ll j = 0; j < i; j++){
ll len = dp[j].size();
for(ll k = 0; k < len; k++){
map<ll, ll> s;
if(a[j][k].size() == 0)
continue;
if(p[i].c <= p[j].c)
continue;
ll len1 = a[j][k].size();
sort(a[j][k].begin(), a[j][k].end());
if(!check(min(a[j][k][0] + k1, a[j][k][0] * k1), max(a[j][k][len1 - 1] + k1, a[j][k][len1 - 1] * k1), p[i].a, p[i].b))
continue;
if(m - i + dp[j][k].num >= n){
for(ll l = 0; l < len1; l++){
ll cc = a[j][k][l] + k1;
if(cc >= p[i].a && cc <= p[i].b && !s[cc]){
a[i][dp[i].size()].push_back(cc);
s[cc] = 1;
}
cc = a[j][k][l] * k1;
if(cc >= p[i].a && cc <= p[i].b && !s[cc]){
a[i][dp[i].size()].push_back(cc);
s[cc] = 1;
}
}
if(a[i][dp[i].size()].size() > 0){
if(dp[j][k].num < n - 1)
dp[i].push_back(node1(dp[j][k].num + 1, j, k));
else{
ok = 1;
sort(a[i][dp[i].size()].begin(), a[i][dp[i].size()].end());
ll t_ans = a[i][dp[i].size()][a[i][dp[i].size()].size() - 1];
ll sum = t_ans;
ll x = j;
ll y = k;
while(x + y != -2){
sort(a[x][y].begin(), a[x][y].end());
ll l = a[x][y][0];
ll r = a[x][y][a[x][y].size() - 1];
if((t_ans - k1) > r || t_ans - k1 < l){
sum += t_ans / k1;
t_ans = t_ans / k1;
}
else if(t_ans / k1 < l || t_ans / k1 > r){
sum += t_ans - k1;
t_ans = t_ans - k1;
}
else{
sum += max(t_ans - k1, t_ans / k1);
t_ans = max(t_ans - k1, t_ans / k1);
}
l = dp[x][y].prex;
r = dp[x][y].prey;
x = l;
y = r;
}
if(sum > ans)
ans = sum;
a[i][dp[i].size()].clear();
}
}
}
}
}
}
if(ok){
printf("YES\n");
printf("%lld\n", ans);
}
else
printf("NO\n");
return 0;
}