p2p网站方案,郑州做网络营销渠道,app定制化开发,网站的优化是什么题解 这么明显的一个dp#xff0c;我怎么就没看出来呢#xff1f;#xff01; 首先我们需要一些前提条件#xff1a;任何划分出来的一个区间的长度不应该超过c。 如果这个区间长度大于c#xff0c;那么设lenn∗cklenn∗ck#xff0c;那么这个区间应该被分成n个长度为c的…题解 这么明显的一个dp我怎么就没看出来呢 首先我们需要一些前提条件任何划分出来的一个区间的长度不应该超过c。 如果这个区间长度大于c那么设lenn∗cklenn∗cklen=n*c+k那么这个区间应该被分成n个长度为c的区间和一个长度为k的区间因为这样的话去掉的元素数量是相同的并且区间更小有利于较小的值不易被取到。因为每次去掉的最小值仅仅是局部最小值不一定是全局最小值。大区间就不一样了虽然大区间去掉的元素数量相同但是这些元素会更小一些。 这样的话我们划分出来的区间应该尽量使得区间的长度为c。 然后我们使用dp来解决剩下的部分 dp[i]dp[i]dp[i]表示前i个元素组成的集合对应的答案。 状态转移方程 策略第i个是否与前c-1个构成一个长为c的区间。 dp[i]min(dp[i−1]a[i],dp[i−c1]sum[i]−sum[i−c]min[i−c1,i])dp[i]min(dp[i−1]a[i],dp[i−c1]sum[i]−sum[i−c]min[i−c1,i])dp[i] = min(dp[i-1]+a[i],dp[i-c+1]+sum[i]-sum[i-c]+min[i-c+1,i]) 由于用到了min[i−c1,i]min[i−c1,i]min[i-c+1,i]我们还需要维护一个最近ccscript typemath/tex idMathJax-Element-339c/script个a元素的最小值方便起见直接使用multiset即可。 反思 以后遇到这种序列题目找出一些必要条件之后一定往dp上多想一想。 代码
#include cstdio
#include set
using namespace std;
typedef long long ll;
const int maxn 100007;
int a[maxn],n,c;
ll dp[maxn],sum[maxn];
multisetint st;
int main(){scanf(%d%d,n,c);for(int i 1;i n;i){scanf(%d,a[i]);dp[i] sum[i] sum[i-1] a[i];}for(int i 1;i c;i)st.insert(a[i]);for(int i c;i n;i){st.insert(a[i]);dp[i] min(dp[i-1] a[i],dp[i-c] sum[i] - sum[i-c] - *st.begin());st.erase(st.find(a[i-c1]));}printf(%lld\n,dp[n]);return 0;
}