蒟蒻吃药计划-治疗系列 #round 2 合并石子+乘积最大



1.合并石子

《信息学奥赛一本通》第五版 P371 第三节 T1

我就直接开始讲吧:

Warning:这个题目和 合并果子 不一样!不一样!不一样!不一样!不一样!不一样!不一样!不一样!

:我想告诉你一个事情,你帮帮我好么?

(内心:mmp怎么又是这个人)

:昨天我去商场的时候,钱包被偷了,银行卡啥的都没了,你能帮帮我么?

(内心:凭啥,我就不帮)

:如果你帮我找到的话,我给你50金币好不好?

(*听到这句话,你充满了决心)

好吧,那我们帮帮他吧,让我们先看看他遇到了什么问题

:那个小偷在我的钱包里留了一张纸条,上面写着一个地址,我昨天到那里去之后看到那儿有几堆石头,上面都有数字,旁边有一块石碑,要我把相邻的两对合并,最后只剩一堆,让花费的体力最小

体力是怎么计算的呢?

:两堆石子合并之后,花费的体力值为两堆石头上的数字的和

好,那我们先和他告别,自己想一想

他已经告诉我们,有 N 堆石子,每堆石子都有对应的一个数字

我们就开一个 stone 数组表示吧

不过要说明一点,为了表示方便,我们把 stone[i] 表示为前 i 堆石子的和

我们再开一个 giver 二维数组,并且让 giver[i][j] 表示为第 i 堆到第 j 堆的石子合并之后花费的最小体力值

那么,我们应该怎么去求得花费最小的体力值呢?

让我们仔细思索一下

先开个循环吧

设有一 i 并使得 i=n-1...1 作为左端点

再设一 j 使得 j=i+1...n 作为右端点

可是这样好像还不够

那我们再弄一个 k 并让 k=i...j-1 把 i 开头 j 结尾的 giver[i][j] 分成两段

k 枚举每一种可能的分段,一步一步推出正确答案!

根据上面的东西,我们就可以推出状态转移方程:

giver[i][j]=min(giver[i][j],giver[i][k]+giver[k+1][j]+stone[j]-stone[i-1]);

对啦!

边界条件:

giver[1...n][1...n]=0;

现在,让我们带着这两个小朋友开始破译这个问题吧!

代码如下:

 1 #include <bits/stdc++.h>
 2 #define fp(i,l,r) for(register int i=(l);i<=(r);++i)
 3 #define fd(i,l,r) for(register int i=(l);i>=(r);--i)
 4 using namespace std;
 5 inline int botposs(int a,int b,int pd){
 6     if(pd==1) return a>b?a:b;
 7     if(pd==0) return a>b?b:a;
 8 }
 9 int main(){
10     int n;
11     int stone[100+20]={0};
12     int giver[100+20][100+20];
13     memset(giver,32,sizeof(giver));
14     stone[0]=0;
15     scanf("%d",&n);
16     fp(i,1,n){
17         int x;
18         scanf("%d",&x);
19         stone[i]=stone[i-1]+x;
20     }
21     fp(i,1,n){
22         giver[i][i]=0;
23     }
24     fd(i,n-1,1){
25         fp(j,i+1,n){
26             fp(k,i,j-1){
27                 giver[i][j]=botposs(giver[i][j],giver[i][k]+giver[k+1][j]+stone[j]-stone[i-1],0);
28             }
29         }
30     }
31     printf("%d",giver[1][n]);
32     return 0;
33 }

合并石子

现在我们去找他吧!

他成功了吗?

:成是成功了,钱包也找回来了,可是解开这个谜题之后,突然出现了一个山洞,里面有一个房间,乌七八黑的,我不敢进去,你再帮帮我好吗?如果成功,我给你100金币

(*你充满了决心)

好吧,我们就再答应他一次吧!



未完待续……

原文地址:https://www.cnblogs.com/Fraction/p/8413340.html

时间: 2024-11-10 07:34:20

蒟蒻吃药计划-治疗系列 #round 2 合并石子+乘积最大的相关文章

蒟蒻吃药计划-治疗系列 #round 3 背包问题大集合

序:部分背包 这一部分的内容是大家再熟悉不过的了 我举个栗子,金银岛 我想学过贪心的差不多都做过这道题 这一类问题有一个特点,就是物品可以分割(或者是可以选择物品的局部) 作为#round 3的序,我希望看过这篇博文的人能够认清这一类问题与后面的各类背包问题的区别 1.01背包 愉快的吃药就从现在开始啦! 按照套路,那个人应该出现了,不是么? :哇,居然被你猜对了 我想,我宁愿自己猜错了 :我今天又有一个问题,你能帮帮我吗? (内心:多少金币?) :不过这次没有金币. (我是拒绝的)什么问题?

蒟蒻吃药计划-治疗系列 #round4 多重背包+混合背包代码存放

1 #include <bits/stdc++.h> 2 #define fp(i,l,r) for(register int i=(l);i<=(r);++i) 3 #define fd(i,l,r) for(register int i=(l);i>=(r);--i) 4 using namespace std; 5 int v[1000+20],w[1000+20],s[1000+20]; 6 int dp[1000+20]; 7 int n,m; 8 inline int

[蒟蒻修炼计划][学习笔记]数论(二)

乘法逆元:若,则称为在意义下的乘法逆元. 本文介绍乘法逆元的三种求法. 扩展欧几里得求逆元 因为,所以设满足, 则可以用扩展欧几里得求关于的方程的一组解,即求出b. inline int exgcd(int a,int b,int &x,int &y){ if(!b){ x=1;y=0;return a; } int ret=exgcd(b,a%b,y,x); y-=a/b*x;return ret; } inline int inver{ r=exgcd(a,p,b,q); if(r!=

[蒟蒻修炼计划][模板]μ函数

省队集训看着台上的老师讲了一上午的莫比乌斯反演,整个人都是懵的,因为我看不清黑板和投影!!! 回家后本来想晚上自学完的,却奈何自己是个拖延症患者,只敲了μ函数(说多了都是泪QAQ) 代码的思路如下: 1.算质因数个数时因为有将1算上,所以每次都需要将符号取反: 2.为什么这样做能算出μ(a)=0呢?证明如下(如果有错可以指出,但别打我QAQ): ①先证明:已知a=p1*p2*p3*...*pn*pi(1<=i<=n且p为质数) 则μ(a)=μ(1)μ(p1)+μ(p2)+...μ(n)+μ(p

[蒟蒻修炼计划][学习笔记]数论(一)

扩展欧几里得 求二元一次不定方程的一组解. 当时,有一组解 : 当时,因为 , 所以设满足, 则 , 整理得 . 所以. 就可以在求gcd的过程中得到一组解. inline int exgcd(int a,int b,int &x,int &y){ if(!b){ x=1;y=0;return a; } else{ int ret=exgcd(b,a%b,y,x); y-=a/b*x;return ret; } } 欧拉函数 欧拉函数的定义:小于等于的正整数中与互质的数的个数. 当时,:

[蒟蒻修炼计划][谜之吐槽]常州集训day3

T1 Description 有K个石子,石子只能放在N条水平线与M条竖直线构成的网格的交点上. 求用K个石子最多能找到多少四边平行于坐标轴的长方形,它的四个角上都恰好放着一枚石子. Input 第一行三个整数N,M,K. Output 一个非负整数,即最多的满足条件的长方形数量. Sample Input 3 3 8 Sample Output 5 HINT N<=30000,保证任意两点不重合,K<=N*M Solution 很显然,最佳的方案长这样: xxx…xxx           

[蒟蒻修炼计划][vijos1002][NOIP2005]过河

Description 给定一条数轴,起点为0,数轴的某些整数点上有石子.每次可以移动的区间为[S,T].求当到达或超过L时,最少踩到的石子数. Input 输入的第一行有一个正整数L(1 <= L <= 10^9). 第二行有三个正整数S,T,M,M表示桥上石子的个数,其中1 <= S <= T <= 10,1 <= M <= 100. 第三行有M个不同的正整数分别表示这M个石子在数轴上的位置(数据保证桥的0和L处没有石子).所有相邻的整数之间用一个空格隔开.

[蒟蒻修炼计划][谜之吐槽]FJ省夏令营day1

T1 Description 给出n个矩形的顶点坐标(每个矩形的底边都在x轴上),求这n个矩形所组成图形的轮廓线的顶点. Input 第一行一个整数n,表示矩形个数. 以下n行,每行3个整数,分别表示矩形的x坐标区间及矩形的高度h[i]. Output 第一行一个整数m,表示轮廓线顶点个数. 以下m行,每行一个坐标表示轮廓线上的顶点.从左到右遍历轮廓线并顺序输出顶点.第一个和最后一个节点的y坐标必然为0. Sample Input 2 3 0 2 4 1 3 Sample Output 6 0

[蒟蒻修炼计划][bzoj1854][SCOI2010]游戏

Description 一个装备有两个属性,一个装备只能被使用一次,一次使用一种属性.攻击boss时需按属性1.属性2.属性3...属性k的顺序使用,问k最大为多少. Input 输入的第一行是一个整数N,表示有N种装备.接下来N行,是对这N种装备的描述,每行2个数字,表示第i种装备的2个属性值. Output 输出一行,包括1个数字,表示k. Sample Input 3 1 2 3 2 4 5 Sample Output 2 HINT 1<=属性值<=10000,N < =10000