Codeforces 119C DP

题意:

有n天,m门课和常数k;

每天上一门课,每门课程有两个属性,最少作业量a,最多作业量b,和难度c。

1<=a<=b<=1e16

c<=100

1<=n<=m<=50 1<=k<=100

要求所有课程的作业量总和最多。

要求除第一天外,其他情况下作业量是前一天加k或者前一天乘k。

输出每天课程的序号,以及该课程应该布置的作业量。

思路:

dp[i][j][k]代表第i门课,第j作业量,第k天的总和。

注意j是相对最少作业量的位移量。

#include<bits/stdc++.h>
using namespace std;
struct st{
    int id,c;
    unsigned long long a,b,num;
};
bool cmp(st a,st b){
    return a.c<b.c;
}
st jilu[100];
unsigned long long dp[55][105][55];
int fi[55][105][55],fj[55][105][55];
stack<pair<unsigned long long,int> >ss;
int main()
{
    int n,m;
    unsigned long long kk;
    scanf("%d%d%I64u",&n,&m,&kk);
    for(int i=0;i<m;i++){
        int tmp;
        scanf("%I64u%I64u%d",&jilu[i].a,&jilu[i].b,&jilu[i].c);
        jilu[i].num=jilu[i].b-jilu[i].a;
        jilu[i].id=i+1;
    }
    sort(jilu,jilu+m,cmp);
    for(int i=0;i<m;i++){
        for(int k=1;k<=n;k++){
            for(int j=0;j<=jilu[i].num;j++){
                if(i==0){
                    if(k==1)
                        dp[i][j][k]=j+jilu[i].a;
                }
                else if(k==1){
                    dp[i][j][k]=j+jilu[i].a;
                }
                else{
                    long long t=jilu[i].a+j-kk;
                    for(int w=0;w<i;w++){
                        if(jilu[w].c>=jilu[i].c)break;
                        if(jilu[w].a>t||jilu[w].b<t)continue;
                        long long tt=t-jilu[w].a;
                        if(dp[w][tt][k-1]){
                            if(dp[i][j][k]<jilu[i].a+j+dp[w][tt][k-1]){
                                dp[i][j][k]=jilu[i].a+j+dp[w][tt][k-1];
                                fi[i][j][k]=w;
                                fj[i][j][k]=tt;
                            }
                        }
                    }
                    t=jilu[i].a+j;
                    if(t%kk==0){
                        t/=kk;
                        for(int w=0;w<i;w++){
                            if(jilu[w].c>=jilu[i].c)break;
                            if(jilu[w].a>t||jilu[w].b<t)continue;
                            long long tt=t-jilu[w].a;
                            if(dp[w][tt][k-1]){
                                if(dp[i][j][k]<jilu[i].a+j+dp[w][tt][k-1]){
                                    dp[i][j][k]=jilu[i].a+j+dp[w][tt][k-1];
                                    fi[i][j][k]=w;
                                    fj[i][j][k]=tt;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    long long ans=0;
    int idi,idj;
    for(int i=0;i<m;i++){
        for(int j=0;j<=jilu[i].num;j++){
            if(ans<dp[i][j][n]){
                ans=dp[i][j][n];
                idi=i;
                idj=j;
            }
        }
    }
    if(ans==0){
        puts("NO");
        return 0;
    }
    while(n--){
        int n_idi=fi[idi][idj][n+1];
        int n_idj=fj[idi][idj][n+1];
        if(n!=0)
            ss.push(make_pair(dp[idi][idj][n+1]-dp[n_idi][n_idj][n],jilu[idi].id));
        else
            ss.push(make_pair(dp[idi][idj][n+1],jilu[idi].id));
        idi=n_idi;idj=n_idj;
    }
    puts("YES");
    while(!ss.empty()){
        pair<unsigned long long,int>t=ss.top();
        ss.pop();
        printf("%d %I64u\n",t.second,t.first);
    }
}
时间: 2024-08-05 12:10:49

Codeforces 119C DP的相关文章

codeforces 449D DP+容斥

Jzzhu and Numbers Time Limit:2000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Appoint description:  System Crawler  (2014-07-20) Description Jzzhu have n non-negative integers a1, a2, ..., an. We will call a sequence o

CodeForces 706C dp

C - Hard problem Time Limit:1000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit Status Practice CodeForces 706C Description Vasiliy is fond of solving different tasks. Today he found one he wasn't able to solve himself, so he as

codeforces的dp专题

1.(467C)http://codeforces.com/problemset/problem/467/C 题意:有一个长为n的序列,选取k个长度为m的子序列(子序列中不能有位置重复),求所取的k个序列求和的最大值是多少 分析:设dp[i][j]在[j,n]范围内取了i个子序列求和所得的最大值,用sum[i]表示[1,i]的求和.转移方程为dp[i][j]=max(dp[i-1][j+m]+sum[j+m-1]-sum[j-1],dp[i][j+1]),表示要不要选择[j,j+m-1]这段为其

codeforces 711C dp

一眼dp,但是这道题不知怎么搞遇到点小问题,又搞了搞才出来,就是给你一些颜色.这个点有颜色,不能图,反之可以.问形成k段连续颜色的最小花费. 纯纯的dp,不知道为什么就是有问题...终于借鉴了别人的A过了,后面再研究吧. #include <cstdio> #include <cstring> #include <vector> #include <cmath> #include <stack> #include <cstdlib>

Codeforces 404D [DP]

/* 我是一个习惯后悔,但是没办法忍受内疚感的二货== 这题是个无脑dp,但是比赛大概20min没出...其实最后5min我好好想想简单化边界条件,可以出的. 题意: 给你一个长度为1e6的由?*01四种字符组成的字符串,类似扫雷,?代表当前不确定,0代表当前无雷,并且 两边无雷,1代表当前五雷且两边有一个雷,2同样的,问当所有格子已知以后一共有多少种可能的局面. 思路: 首先想到的是,这个问题无后效性,而当前位置的合法方式只与它之前的两位有关. 所以dp的思路也是显而易见的,即dp[i][j]

codeforces 608C:(dp)

从又往左点灯塔,点亮一个的同时,往左di范围内的灯塔全部被破坏.现在能在最右端按一个灯塔,攻击范围任意,问到最后最少有几个灯塔留下 用dp瞎搞.具体看代码吧 #include"cstdio" #include"queue" #include"cmath" #include"stack" #include"iostream" #include"algorithm" #include&quo

Codeforces 721C [dp][拓扑排序]

/* 题意:给你一个有向无环图.给一个限定t. 问从1点到n点,在不超过t的情况下,最多可以拜访几个点. 保证至少有一条路时限不超过t. 思路: 1.由无后向性我们可以知道(取决于该图是一个DAG),这题一定可以dp. 2.dp[i][j]代表,到达点i,并且拜访了j个城市的最短时间. wa点: 没有初始化数组中的0.. */ #include<bits/stdc++.h> #define N 5050 using namespace std; int inf=0x3f3f3f3f; int

CodeForces 607C (DP) Hard problem

题目:这里 题意:给定n个字符串,每个字符串可以进行一项操作,就是将这个字符串交换,就是该字符串的第一个和最后一个交换,第二个和倒数第二个交换,以此类推,当然可以选择对于 该字符串进行或不进行这项操作,而每个字符串都有一个相应的能量值,进行操作了就要消耗那么多能量值,最后是否能在消耗的能量值最小的情况下保证这些字符串是升序的( 字典序从小到大),不能就输出-1. 字符串用string,DP,dp[i][j]表示到第i个字符串的状态为j的时候(j为1表示这个串交换了,j为0表示这个串没有交换),注

CodeForces 567F DP Mausoleum

1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <map> 7 #define MP make_pair 8 using namespace std; 9 10 typedef long long LL; 11 12 const int maxn =