CSP初赛复习-28-动态规划-区间动态规划
CSP初赛复习-28-动态规划-区间动态规划
前缀和
对于一个给定的数列,它的前缀和数列中表示从第1个元素到第i个元素的总和。

示例1

前缀和可以直接通过递推公式计算
S[i]=S[i-1]+A[i]//S[i-1]表示1~i-1所有元素的和,加上A[i]就构成了1~i个元素的和
区间和
表示连续区间的和
例1 示例1中,1~3的区间和
3个元素相加
A[2]+A[3]+A[4]=2+3+4=9
通过前缀和计算
S[j]-s[i-1]=s[4]-s[1]=10-1=9
--
S[1]=A[1]
s[4]=A[1]+A[2]+A[3]+A[4]
s[4]-S[1]=A[2]+A[3]+A[4]
例2 示例1中,3~6的区间和
4个元素相加
A[3]+A[4]+A[5]+A[6]=3+4+5+6=18
通过前缀和计算
S[j]-s[i-1]=s[6]-s[2]=21-3=18
--
S[2]=A[1]+A[2]
s[6]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]
s[4]-S[1]=A[3]+A[4]+A[5]+A[6]
题目描述
给定n个正整数组成的数列a[1] , a[2] , a[3] ...a[n]和m个区间[L,R],分别求这m个区间的区间和,对于所有测试数据,
n,m<=10^5 , a[i]<=10^4
输入格式
第一行,为一个正整数n
第二行,为n个正整数a[1] , a[2] , a[3] ...a[n]
第三行,为一个正整数m
接下来m行,每行为两个正整数L,R,满足1<=L<=R<=n
输出格式
共m行
第i行为第i组的答案询问
输入样例
4
4 3 2 1
2
1 4
2 3
输出样例
10
5
大致思路
1 可以通过循环求单个区间和 ,时间复杂度最大10^5,如果区间也达到最大值 10 ^5,则可能超时
2 可以通过递推先计算所有元素的前缀和,时间复杂度最大10^5
3 再进行m次循环,每次询问直接随机读取,m次询问时间复杂度最大10^5,时间不会超时
参考程序
#include<iostream>
using namespace std;
const int N=1e5+10;
int a[N],s[N];//a[N]原始数组 s[N]前缀和数组
int main(){
int n,m;
cin>>n;
for(int i=1;i<=n;i++){//输入n个正整数
cin>>a[i];
}
for(int i=1;i<=n;i++){//通过递推求前i项的前缀和
s[i]=s[i-1]+a[i];
}
cin>>m;//输入m个询问区间 C++
while(m--)//逐一询问
{
int L,R;
cin>>L>>R;//L区间左端点 R区间右端点
cout<<s[R]-s[L-1]<<endl;//根据前缀和求区间和
}
return 0;
}
区间动态规划
区间动态规划,就是动态规划过程中求一个区间的最优解。通过将一个大的区间分为很多个小的区间,求其小区间的解,然后一个一个的组合成一个大的区间而得出最终解。
题目描述
设有N(N<=300)堆石子排成一排,其编号为1,2,3...N,每堆石子有一定的质量m[i] (m[i]<=1000).现在要将这N堆石子合并成为一堆.每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻。合并时由于选择的顺序不同,合并的总代价也不相同。试找出一种合理的方法,使总的代价最小,并输出最小代价
输入格式
第一行,一个整数N
第二行,N个整数m[i]
输出格式
输出文件仅一个整数,也就是最小代价
输入样例
4
2 5 3 1
输出样例
22
大致思路
1 计算前缀和数组,可以后续合并区间时直接求区间和
2 枚举所有区间长度
3 根据区间长度枚举左右端点,每个区间合并枚举i~j每个区间,合并时包括3部分
i~k 合并成一堆的最小代价dp[i][k]
k+1 ~ j 合并成一堆的最小代价 dp[k+1][j]
i~j 合并成一堆的代价 sum[j]-sum[i-1]

参考程序
#include<bits/stdc++.h>
using namespace std;
//dp[i][j]所有将区间i~j合并成一堆的最小代价
int dp[310][310],len,a[310],n,sum[310];
int main(){
cin>>n;
for(int i=1;i<=n;i++){//输入n个数 求前n个数的前缀和
cin>>a[i];
sum[i]=sum[i-1]+a[i];
}
for(int len=2;len<=n;len++){//枚举所有可能合并区间长度2~n
for(int i=1;i<=n-len+1;i++){//左端点1~n-len+1 保证有len的长度
int j=i+len-1;//右端点
dp[i][j]=1e8;//求最小默认最大
for(int k=i;k<j;k++){
//任意区间最后一步合并一定是2个区间合并
//这2个区间合并最小代价为 左边最小代价+右边最小代价+左右合并代价
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
}
}
}
cout<<dp[1][n];//所有将区间1~n合并成一堆的最小代价
}
CSP初赛复习-28-动态规划-练习题
https://www.cnblogs.com/myeln/articles/17626730.html
作者:newcode 更多资源请关注纽扣编程微信公众号

从事机器人比赛、机器人等级考试、少儿scratch编程、信息学奥赛等研究学习

浙公网安备 33010602011771号