dp专场的蒟蒻题解

前言:一直想练练dp,正好衣神弄了个训练赛。。上次看cgold大佬的题解心血来潮所以自己试着写了第一次题解。。可惜本蒟蒻的能力太差有两道题做不太出,只好搬运学习其它大佬的题解了。。

a题

https://vjudge.net/contest/355951#problem/A

这题做题的过程十分痛苦

我又双叒叕看错题意了。。

以为是必须在对角线上

其实是随便n*n的都行。。

大概思路是从一个角开始更新,统计左边和上边相同的长度

#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#include <sstream>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define Mod 1000000007
#define eps 1e-6
#define ll long long
#define INF 0x3f3f3f3f
#define MEM(x,y) memset(x,y,sizeof(x))
#define Maxn 100005
#define P pair<int,int>
using namespace std;
char a[1005][1005];
int dp[1005][1005];
int n;

int main()
{
    int n, ans;
    while (cin>>n , n)
    {
        ans = 1;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
            {
                cin >> a[j][i];
            }
        for (int i = 0; i < n; i++)
        {
            for (int j = n - 1; j >= 0; j--)
            {
                dp[i][j] = 1;
                if (i == 0 || j == n - 1) continue;
                int q = dp[i - 1][j + 1];
                for (int k = 1; k <= q; k++)
                {
                    if (a[i - k][j] == a[i][j + k]) dp[i][j]++;
                    else break;
                }
                ans = max(ans, dp[i][j]);
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

b题

https://vjudge.net/contest/355951#problem/B

这题有点难。。

蒟蒻直接下线。。。

那就学下网上大佬的方法吧

dp(j, k)表示,取j 个候选人,使其辩控差为k 的所有方案中,辩控和最大的那个方案(该方案称为“方案dp(j, k)”)的辩控和

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
using namespace std;

#define N 220
#define met(a, b) memset(a, b, sizeof(a))
#define INF 0xffffff
const long long  Max = 2000000000;
typedef long long LL;

int D[N], P[N];
int dp[30][1000];  ///dp[i][k]代表选 i 个人, 辩控差为 k 的辩控和最大
int pre[30][1000]; ///pre[i][k] 存的是它是上次选的人
int Answer[N];     ///记录选中的这 m 个人的编号

int main()
{
    int n, m, iCase=1;

    while(scanf("%d%d", &n, &m), n||m)
    {
        int i, j, k, Min, t1, t2;

        met(D, 0);
        met(P, 0);
        met(dp, -1);
        met(pre, 0);
        met(Answer, 0);

        for(i=1; i<=n; i++)
            scanf("%d%d", &D[i], &P[i]);

        Min = m*20; ///它的辩控差最大为 m*20
        dp[0][Min] = 0;  ///起始状态要先置为 0

        /// k 的最大取值范围是[-Min, Min], 但是数组不能表示负数, 因此将数组向右平移 Min,得到[0, 2*Min]
        for(i=0; i<=m; i++)
        {
            for(k=0; k<=Min*2; k++)
            {
                if(dp[i][k]==-1) continue;  ///如果存在,接着找 dp[i][k] 的下一个状态

                for(j=1; j<=n; j++)
                {
                        if(dp[i+1][k+D[j]-P[j]] < dp[i][k]+D[j]+P[j])
                        {
                            t1=i, t2=k;

                            while(t1>0 && pre[t1][t2]!=j)
                            {
                                t2 -= D[pre[t1][t2]] - P[pre[t1][t2]];
                                t1 --;
                            }
                            if(t1==0)   ///当 t1 为 0 时,编号为 j 这个人在之前没有被选中过
                            {
                                dp[i+1][k+D[j]-P[j]] = dp[i][k] + D[j] + P[j];
                                pre[i+1][k+D[j]-P[j]] = j;
                            }
                        }

                }
            }
        }

        int ff = Min;
        int num = 0, sum1=0, sum2=0;

        ///要选辩控差最小的,所求的 num 便是选 m 个人辩控差最小的
        while(dp[m][ff-num]==-1 && dp[m][ff+num]==-1) num++;

        if(dp[m][ff-num]>dp[m][ff+num]) t2 = ff-num;
        else    t2 = ff+num;

        t1 = m;

        for(i=1; i<=m; i++)
        {
            Answer[i] = pre[t1][t2];

            sum1 += D[Answer[i]];
            sum2 += P[Answer[i]];

            t1--;
            t2 -= D[Answer[i]] - P[Answer[i]];
        }

        printf("Jury #%d\n", iCase++);
        printf("Best jury has value %d for prosecution and value %d for defence:\n", sum1, sum2);

        sort(Answer+1, Answer+1+m);

        for(i=1; i<=m; i++)
            printf(" %d", Answer[i]);

        printf("\n\n");
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/cyq123/p/12296640.html

时间: 2024-08-05 20:30:50

dp专场的蒟蒻题解的相关文章

【铺地毯】蒟蒻题解

原题:传送门 本蒟蒻的题解,让大神们见笑了! 从上图,大家可以发现一点:后铺的地毯要比先铺的位置要更靠上,这点很重要. \(OK\),开始进入代码讲解. #include<iostream> using namespace std; int a[10001],b[10001],g[10001],k[10001],n,i,j,d,x,y; int main() { cin>>n; for(d=1;d<=n;d++) cin>>a[d]>>b[d]>

【单词方阵】蒟蒻题解

题目:传送门 题外闲话 这道题是一个\(DFS\)(深度优先搜索 \(Depth\) \(Frist\) \(Sreach\))的题目,可是-我就是不想敲递归(我绝对不会告诉你我是想偷懒的),于是就有了这个程序和这篇题解-- 题目分析 首先,这是一个二维的题目,要寻找8个方向,如下图所示: (-1,-1) (-1, 0) (-1, 1) ( 0,-1) 在这向八个方向寻找 ( 0,1) (1,-1) (1,0) (1,1) 所以,要预处理八个方向: int dx[8]={-1,-1,-1,0,0

【跳马问题】蒟蒻题解

原题:传送门 上来先看(鬼畜的题目背景)题目描述.一看就是一个二维的深搜. 有芥末一条马,只会往右跳(话说它左腿系不系瘸了)日字形. 再一看数据范围,n,m<=18.等等,半棋盘不是只有4行6列吗?算了,跟\(OI\)讲什么道理啊. 好了,闲话完毕,步入正题. #include<iostream> using namespace std; 为了用坐标模拟马向右跳的动作,就要写一个坐标变化表. int dx[4]={2,-2,1,-1},dy[4]={1,1,2,2};//模拟坐标x,y的

DP——由蒟蒻到神犇的进阶之路

问:为什么开dp专题? 答:我太蒟蒻了 问:你个辣鸡,衡八的那个陈老师不知道比你强到哪里去了,你们这些年轻人,拿衣服! 答:--------------------------------------------------------------[我是辣鸡,只能膜陈老师] 一.Hzwer博客中的树形DP集合[待更]

USACO 简易题解(蒟蒻的题解)

蒟蒻难得可以去比赛,GDOI也快到了,还是认真刷题(不会告诉你之前都在颓废),KPM 神犇既然都推荐刷USACO, 辣就刷刷. 现在蒟蒻还没刷完,太蒟刷得太慢,so 写了的搞个简易题解(没代码,反正NOCOW一堆) x_y_z(表示 Section x.y 的第z题) 1_1_1 这个..... ASCII码搞一搞就好了吧... 1_1_2 直接模拟,注意均分后剩下的钱还是他的 1_1_3 日期的题最难受了,直接模拟往下推就好了 1_1_4 枚举断开的位置,然后爆枚左右,注意处理 w 如果左右第

noip2013Day2T3-华容道【一个蒟蒻的详细题解】

描述 小 B 最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面,华容道是否根本就无法完成,如果能完成,最少需要多少时间. 小 B 玩的华容道与经典的华容道游戏略有不同,游戏规则是这样的: 在一个 n*m 棋盘上有 n*m 个格子,其中有且只有一个格子是空白的,其余 n*m-1个格子上每个格子上有一个棋子,每个棋子的大小都是 1*1 的: 有些棋子是固定的,有些棋子则是可以移动的: 任何与空白的格子相邻(有公共的边)的格子上的棋子都可以移动到空白

蒟蒻ACMer回忆录 &#183; 一段弱校ACM的奋斗史

三年半的ACM生涯终于迎来了终点,退役之时,感慨万分,故写此文以纪念逝去的时光,那些为ACM拼搏的日子,那段弱校ACM的奋斗史. 三年半的ACM生涯,窝见证了CUMT从打铁到铜牌的突破,又见证了从铜牌到银牌的突破:见证了集训队员从3人发展到10余人,又见证了ACM实验室的落实. 三年半的ACM生涯,窝经历了太多,有Accepted时的欢笑,有Wrong Answer时的沮丧,有Time Limit Exceeded时的无奈,有Runtime Error时的尴尬,有打铁的失落,有拿牌的惊喜. 13

蒟蒻修养之cf紫名计划

因为太弱,蒟蒻我从来没有上过div1(这就是今年的最后愿望啊啊啊啊啊)................打cf几乎每次都是fst...........所以我的cf成绩图出现了惊人了正弦函数图像............. 所以这个礼拜刷div1的abc(估计只能a和b?)..............学习各位神犇直接简略题解吧............... 2 [494A]裸构造...每个#取1最后一个取完即可... [494B]裸DP...以b的下标设状态...这么水的题我不会说我想了很久哒....

bzoj 4636: 蒟蒻的数列

4636: 蒟蒻的数列 Description 蒟蒻DCrusher不仅喜欢玩扑克,还喜欢研究数列 题目描述 DCrusher有一个数列,初始值均为0,他进行N次操作,每次将数列[a,b)这个区间中所有比k小的数改为k,他想知 道N次操作后数列中所有元素的和.他还要玩其他游戏,所以这个问题留给你解决. Input 第一行一个整数N,然后有N行,每行三个正整数a.b.k. N<=40000 , a.b.k<=10^9 Output 一个数,数列中所有元素的和 Sample Input 4 2 5