bzoj 1133: [POI2009]Kon dp

1133: [POI2009]Kon

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 242  Solved: 81
[Submit][Status][Discuss]

Description

火车沿途有N个车站,告诉你从每一站到每一站的人数,现在查票员只能查K次票,每次查票可以控制目前在车上的所有乘客的车票。求一个查票方案,使得控制的不同的乘客尽量多。 (显然对同一个乘客查票多次是没有意义的,只算一次)

Input

第一行正整数 N K (1≤K<N≤600, K≤50). 接下来N-1行,第i行第j个数描述第i站上,到第i+j站下的乘客个数。总乘客数≤2*10^9

Output

单调增的K个整数,用空格隔开,表示经过哪些站以后查票。

Sample Input

7 2
2 1 8 2 1 0
3 5 1 0 1
3 1 2 2
3 5 6
3 2
1

Sample Output

2 5

  还是对这种字典序dp的实现方法非常不熟悉,以后看到字典序首先思考dp方向,然后注意废状态的处理,我由于dp数组最开始没有把状态赋为-INF,从而有些状态由一些废状态转移过来了,wa了很久。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 660
#define INF 0x3f3f3f3f
int dp[55][MAXN];
int tot[MAXN][MAXN];
int stot[MAXN][MAXN];
int tot2[MAXN][MAXN];
int stot2[MAXN][MAXN];
int pv[MAXN][MAXN];

int main()
{
        //freopen("input.txt","r",stdin);
        int n,m;
        scanf("%d%d",&n,&m);
        for (int i=1;i<=n;i++)
                for (int j=i+1;j<=n;j++)
                        scanf("%d",&tot[i][j]),tot2[j][i]=tot[i][j];
        for (int i=1;i<=n;i++)
                for (int j=i+1;j<=n;j++)
                        stot[i][j]=stot[i][j-1]+tot[i][j];
        for (int i=1;i<=n;i++)
                for (int j=1;j<i;j++)
                        stot2[i][j]=stot2[i][j-1]+tot2[i][j];
        for (int i=0;i<MAXN;i++)
                for (int j=0;j<MAXN;j++)
                        dp[i][j]=-INF;
        for (int i=1;i<=n;i++)
                dp[0][i]=0;
        for (register int p=1;p<=m;p++)
        {
                for (int i=1;i<=n;i++)
                {
                        int v=0;
                        for (int k=i;k<n;k++)
                        {
                                v+=stot[k][n];
                                v-=stot2[k][k-1]-stot2[k][i-1];
                                if (dp[p][i]<dp[p-1][k+1]+v)
                                {
                                        dp[p][i]=dp[p-1][k+1]+v;
                                        pv[p][i]=k+1;
                                }
                        }
                }
        }
        //printf("%d\n",dp[m][1]);
        int cur=1;
        for (int i=0;i<m-1;i++)
        {
                cur=pv[m-i][cur];
                printf("%d ",cur-1);
        }
        cur=pv[m-(m-1)][cur];
        printf("%d",cur-1);
        printf("\n");
}
时间: 2024-08-24 12:22:53

bzoj 1133: [POI2009]Kon dp的相关文章

BZOJ 1133 POI2009 Kon 动态规划

题目大意:给定n个站点,每个人都会在某个站点上车并在之后的某个站点下车,查票员可以在两个站点之间查票,问查票k次最多查到多少人 壮哉我大轻音部(误 令f[i][j]表示当前在第i个点和第i+1个点之间查票,已经查了j次的最大收益 枚举上一次查票的位置,统计比上一次能多查出来的人数即可 时间复杂度O(kn^2) 输出方案记录一下上一次查票的位置即可 由于没有SPJ所以要输出字典序最小的方案 注意有组全零的数据 3 2 0 0 0 0 0 0 #include <cstdio> #include

BZOJ 1087状态压缩DP

状态压缩DP真心不会写,参考了别人的写法. 先预处理出合理状态, 我们用二进制表示可以放棋子的状态,DP[I][J][K]:表示现在处理到第I行,J:表示第I行的状态,K表示现在为止一共放的棋子数量. #include<stdio.h> #include<iostream> #define N 1111 using namespace std; typedef long long ll; int num,n,m; ll dp[11][1<<11][90]; int hh

BZOJ 1237 配对(DP)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1237 题意:给出两个n元素的数列A和B.为A中的每个元素在B中为其找一个配对的元素(配对的元素不能相等,B中每个元素只能被使用一次),使得所有配对的两个数的差的绝对值之和最小? 思路:首先排序,若无配对元素不能相等这一 限制,则排序后一一匹配即可.有了这个限制,那么对于相等的元素就要在其前后进行调整,显然,与距离较远的调整不如与距离近的调整优.那么,需要在多大的 范围内调整才能保证最优

bzoj 3437 斜率优化DP

写题解之前首先要感谢妹子. 比较容易的斜率DP,设sum[i]=Σb[j],sum_[i]=Σb[j]*j,w[i]为第i个建立,前i个的代价. 那么就可以转移了. 备注:还是要感谢妹子. /************************************************************** Problem: 3437 User: BLADEVIL Language: C++ Result: Accepted Time:3404 ms Memory:39872 kb **

bzoj 1138: [POI2009]Baj 最短回文路 dp优化

1138: [POI2009]Baj 最短回文路 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 161  Solved: 48[Submit][Status] Description N个点用M条有向边连接,每条边标有一个小写字母. 对于一个长度为D的顶点序列,回答每对相邻顶点Si到Si+1的最短回文路径. 如果没有,输出-1. 如果有,输出最短长度以及这个字符串. Input 第一行正整数N和M ( 2 ≤ N ≤ 400 , 1 ≤ M ≤

BZOJ 1138 [POI2009]Baj 最短回文路 DP

题意:链接略 方法: DP 解析: 显然我们可以找回文中点然后宽搜向两边拓展. 不过这样的复杂度的话- 枚举中点再拓展,岂不有点爆炸? 所以我们换个方式来优化. 我们设F[i][j]表示由i到j的最短回文路径长度. 设G[i][j][k]表示从i到j走一条回文路径再走一个小写字母k的最短回文路径长度. 有了这个辅助式子,问题就变得简单多了. 所有的状态最多也就n^2*k个. 直接上宽搜即可. F[i][j]=min{G[z][j][k]+1&&edge[i][z]==k} G[i][j][

[BZOJ 3791] 作业 【DP】

题目链接:BZOJ - 3791 题目分析 一个性质:将一个序列染色 k 次,每次染连续的一段,最多将序列染成 2k-1 段不同的颜色. 那么就可以 DP 了,f[i][j][0|1] 表示到第 i 个位置,染了 j 段,当前这一段颜色为 0|1 的最大价值. f[i][][] 只与 f[i-1][][] 有关,第一维用滚动数组就可以了. 代码 #include <iostream> #include <cstdio> #include <cstring> #inclu

[BZOJ 2165] 大楼 【DP + 倍增 + 二进制】

题目链接:BZOJ - 2165 题目分析: 这道题我读了题之后就想不出来怎么做,题解也找不到,于是就请教了黄学长,黄学长立刻秒掉了这道题,然后我再看他的题解才写出来..Orz 使用 DP + 倍增 ,用状态 f[x][i][j] 表示从 i 出发,坐 x 次电梯到达 j ,最多能上升的层数.开始读入的就是 f[1][][] 数组.(注意:若开始时 i 不能走到 j , 则 f[1][i][j] = -INF) 使用倍增,用 f[x][][] 求出 f[x << 1][][] , 一直求f[2

BZOJ 4380 [POI2015]Myjnie | DP

链接 BZOJ 4380 题面 有n家洗车店从左往右排成一排,每家店都有一个正整数价格p[i]. 有m个人要来消费,第i个人会驶过第a[i]个开始一直到第b[i]个洗车店,且会选择这些店中最便宜的一个进行一次消费.但是如果这个最便宜的价格大于c[i],那么这个人就不洗车了. 请给每家店指定一个价格,使得所有人花的钱的总和最大. Input 第一行包含两个正整数n,m(1<=n<=50,1<=m<=4000). 接下来m行,每行包含三个正整数a[i],b[i],ci Output 第