分羊(区间dp:分治与决策单调性优化)
生活随笔
收集整理的這篇文章主要介紹了
分羊(区间dp:分治与决策单调性优化)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 題目描述
- 樣例輸入
- 樣例輸出
- 解析
- 代碼
題目描述
給你一個數列,分成m段,每段的價值為相同數對的對數
求最小價值和
樣例輸入
10 2
1 2 1 2 1 2 1 2 1 2
樣例輸出
8
解析
容易想到區間dp
定義dp[i][j]:把前i個數分成j段的最小價值
那么枚舉最后一段斷點的位置,轉移就是:
dp[i][j]=min(dp[i][j],dp[k][j-1]+calc(k+1,i)
(1<=k<i)
不難發現本題是符合決策單調性的
就可以利用這個進行優化啦
使用分治思路
還有一個問題是關于calc的計算
可以使用一個類似于簡化的莫隊的思路,維護兩個指針即可
這樣就完事啦
代碼
#include<bits/stdc++.h> using namespace std; #define ll long long const int N=1e5+100; int m,n; int a[N],buc[N]; int l=1,r=0; ll sum=0; ll add(int x){return buc[a[x]]++;} ll del(int x){return --buc[a[x]];} ll calc(int nl,int nr){while(r<nr) sum+=add(++r);while(r>nr) sum-=del(r--);while(l>nl) sum+=add(--l);while(l<nl) sum-=del(l++);return sum; } ll dp[N][30]; int now; void solve(int x,int y,int px,int py){if(x>y) return;int mid=x+y>>1,pl; // printf("x=%d y=%d px=%d py=%d\n",x,y,px,py);dp[mid][now]=2e16;for(int i=px;i<=min(py,mid-1);i++){if(dp[mid][now]>dp[i][now-1]+calc(i+1,mid)){pl=i;dp[mid][now]=dp[i][now-1]+calc(i+1,mid); // printf("mid=%d k=%d pl=%d dp=%d\n",mid,now,pl,dp[mid][now]);}} // printf("x=%d y=%d px=%d py=%d mid=%d dp=%lld\n",x,y,px,py,mid,dp[mid][now]);solve(x,mid-1,px,pl);solve(mid+1,y,pl,py); } int main(){ // freopen("dp.in","r",stdin); // freopen("dp.out","w",stdout);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++){scanf("%d",&a[i]);}for(int i=1;i<=n;i++){dp[i][1]=calc(1,i); // printf("i=%d k=1 dp=%lld\n",i,dp[i][1]);}for(int k=2;k<=m;k++){now=k;solve(1,n,0,n);//for(int i=1;i<=n;i++) printf("i=%d k=%d dp=%lld\n",i,k,dp[i][k]);}printf("%lld\n",dp[n][m]); } /* 10 2 1 2 1 2 1 2 1 2 1 25 2 1 1 1 1 1 */總結
以上是生活随笔為你收集整理的分羊(区间dp:分治与决策单调性优化)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 英雄联盟硬件配置要求(英雄联盟什么电脑配
- 下一篇: 猜数(二分、线段树)