首页 > 其他分享 >决策单调性优化dp二则

决策单调性优化dp二则

时间:2022-11-23 21:44:37浏览次数:59  
标签:maxx ch int mid dp 二则 单调 define

Ciel and Gondolas  CodeForces - 321E

题意:有n个人,第i个人和第j个人放在一起时会产生a[i][j]的沮丧值(是社恐吗),保证a[i][j]=a[j][i],两个人只产生一份沮丧值。将n个人分成连续的k组,每组产生的沮丧值是这组人两两之间产生的沮丧值之和。求所有沮丧值的最小值。

解:设dp[i][j]为将前j个人分为i组,显然有dp[i][j]=min(dp[i-1][k]+sum(k,j)). 现在sum(k,j)和k有关系了,不能用单调队列优化。引入决策单调性。对于每一个dp[i][j],都会选择一个k进行转移,称k为决策点。决策单调性指后作出决策所选择的决策点,一定不在之前决策选择的决策点前面。

推荐读物:关于决策单调性优化动态规划

这道题属于上文中决策点之间不影响的情况,可以用分治实现。但一开始写了二分,然后T飞了……存个代码。

代码:

#include <bits/stdc++.h>
using namespace std;
#define maxx 4005
#define maxn 25
#define maxm 205
#define ll long long
#define inf 1000000009
#define mod 2520
int dp[805][maxx]={0};
int sum[maxx][maxx]={0};
int q[maxx]={0};
int n,k;
int read(int res = 0) {char ch = getchar(); while (!isdigit(ch)) ch = getchar(); while (isdigit(ch)) res = res * 10 + (ch - '0'), ch = getchar(); return res;}
int cal(int l,int r){
    return (sum[r][r]-sum[l-1][r]-sum[r][l-1]+sum[l-1][l-1])/2;
}
int get(int s,int e,int i){
    int l=e+1,r=n;
    int res=0x3f3f3f3f;
    while(l<=r){
        int mid=(l+r)/2;
        if(dp[i-1][s]+cal(s+1,mid)>=dp[i-1][e]+cal(e+1,mid)){
            res=mid;
            r=mid-1;
        }
        else{
            l=mid+1;
        }
    }
    return res;
}
signed main() {
    n=read();
    k=read();
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            int w=read();
            sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+w;
        }
    }
    for(int i=1;i<=n;i++){
        dp[0][i]=0x3f3f3f3f;
    }
    for(int i=1;i<=k;i++){
        int head=1,tail=1;
        q[1]=0;
        for(int j=1;j<=n;j++){
            while(head<tail&&get(q[head],q[head+1],i)<=j) head++;
            dp[i][j]=dp[i-1][q[head]]+cal(q[head]+1,j);
            while(head<tail&&get(q[tail-1],q[tail],i)>=get(q[tail],j,i)) tail--;
            q[++tail]=j;
        }
    }
    printf("%d\n",dp[k][n]);
    return 0;
}
//dp[i][j]=min(dp[i-1][k]+val(k+1,j))
View Code

分治代码:

#include <bits/stdc++.h>
using namespace std;
#define maxx 4005
#define maxn 25
#define maxm 205
#define ll long long
#define inf 1000000009
#define mod 2520
int dp[805][maxx]={0};
int sum[maxx][maxx]={0};
int n,k;
inline int read(){
    int x=0; char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar());
    for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
    return x;
}
int cal(int l,int r){
    return (sum[r][r]-sum[l-1][r]-sum[r][l-1]+sum[l-1][l-1])/2;
}
int ii;
void solve(int l,int r,int s,int e){
    if(r<l||e<s) return;
    if(s==e){
        //printf("%d %d\n",l,r);
        for(int i=l;i<=r;i++){
            dp[ii][i]=dp[ii-1][s]+cal(s+1,i);
        }
        return;
    }
    int mid=(l+r)/2;
    int ans=s;
    for(int i=s;i<mid&&i<=e;i++){
        if(dp[ii][mid]>dp[ii-1][i]+cal(i+1,mid)){
            dp[ii][mid]=dp[ii-1][i]+cal(i+1,mid);
            ans=i;
        }
    }
    solve(l,mid-1,s,ans);
    solve(mid+1,r,ans,e);
}
signed main() {
    n=read();
    k=read();
    int x;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            x=read();
            sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+x;
        }
    }
    memset(dp,0x3f,sizeof dp);
    for(int i=0;i<=k;i++){
        dp[i][0]=0;
    }
    for(int i=1;i<=n;i++){
        dp[1][i]=cal(1,i);
    }
    for(int i=2;i<=k;i++){
        ii=i;
        solve(1,n,0,n-1);
    }
    printf("%d\n",dp[k][n]);
    return 0;
}
//dp[i][j]=min(dp[i-1][k]+val(k+1,j))
View Code

感觉这样的优化把第一次决策预处理好会舒服一点。

Yet Another Minimization Problem  CodeForces - 868F

题意:把上题的价值改为子数组内能组成多少两个元素相同的二元组,比如n个2可以组成n*(n-1)/2个这样的二元组,n不必须连续。

解:啊和上题套路一样一样的,处理val的时候用一种类似于莫队的方法,暴力加减(

代码:

#include <bits/stdc++.h>
using namespace std;
#define maxx 100005
#define maxn 25
#define maxm 205
#define ll long long
#define inf 1000000009
#define mod 2520
ll dp[25][maxx]={0};
int a[maxx]={0};
int n,k;
ll cnt[maxx]={0};
ll ans=0;
int L=1,R=1;
void upd(int c,int d){
    ans+=d*cnt[c]*(cnt[c]-1)/2;
}
ll cal(int l,int r){
    while(L<l) upd(a[L],-1),cnt[a[L]]--,upd(a[L],1),L++;
    while(L>l) L--,upd(a[L],-1),cnt[a[L]]++,upd(a[L],1);
    while(R>r) upd(a[R],-1),cnt[a[R]]--,upd(a[R],1),R--;
    while(R<r) R++,upd(a[R],-1),cnt[a[R]]++,upd(a[R],1);
    return ans;
}
int ii;
void solve(int l,int r,int s,int e){
    if(l>r||s>e) return;
    if(s==e){
        for(int i=l;i<=r;i++){
            dp[ii][i]=dp[ii-1][s]+cal(s+1,i);
        }
        return;
    }
    int mid=(l+r)/2,p=l;
    for(int i=s;i<mid&&i<=e;i++){
        if(dp[ii][mid]>dp[ii-1][i]+cal(i+1,mid)){
            dp[ii][mid]=dp[ii-1][i]+cal(i+1,mid);
            p=i;
        }
    }
    solve(l,mid-1,s,p);
    solve(mid+1,r,p,e);
}
signed main() {
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    cnt[a[1]]++;
    memset(dp,0x3f,sizeof dp);
    for(int i=1;i<=n;i++){
        dp[1][i]=cal(1,i);
    }
    for(int i=0;i<=k;i++){
        dp[0][i]=0;
    }
    for(int i=2;i<=k;i++){
        ii=i;
        solve(1,n,0,n-1);
    }
    printf("%lld\n",dp[k][n]);
    return 0;
}
//dp[i][j]=min(dp[i-1][k]+val(k+1,j))
View Code

 

标签:maxx,ch,int,mid,dp,二则,单调,define
From: https://www.cnblogs.com/capterlliar/p/16920221.html

相关文章

  • AIR32F103(六) ADC,I2S,DMA和ADPCM实现录音播放功能
    目录AIR32F103(一)合宙AIR32F103CBT6开发板上手报告AIR32F103(二)Linux环境和LibOpenCM3项目模板AIR32F103(三)Linux环境基于标准外设库的项目模板AIR32F103(四)2......
  • Luogu P1453 城市环路(基环树DP)
    法一:dsu#include<bits/stdc++.h>usingll=longlong;usingnamespacestd;constintN=100010;structnode{intv,nxt;}e[N......
  • BizTalk Adpter Pack for MySap 的安装
     BizTalkAdpterPackforMySap的安装方法:1,首先安装必需两个SAPLIB,1.librefc32u.dll2.libsapu16vc80.dll,这两个文件的来源可以在安装了sapgui的客户端......
  • oracle 数据库表空间的备份 ( expdp + cron )
    首先使用expdp工具制作一个备份脚本:backup.sh #hs_aws_dbprdbackup#byxulong#2010-09-25exportORACLE_SID=hsoaexportORACLE_UNQNAME=hsoaexportORACLE_BASE=/......
  • WordPress编辑器支持Word图文一键导入
    ​ ueditor粘贴不能粘贴word中的图片是一个很头疼的问题,在我们的业务场景中客户要求必须使用ueditor并且支持word的图片粘贴,因为这个需求头疼了半个月,因为前端方面因为安......
  • wordpress 火车头发布模块
    <html><head><metahttp-equiv="Content-Type"content="text/html;charset=UTF-8"><title>免登陆WordPress发布接口</title></head><body><p>最新版本或者意......
  • 数字化安全生产平台 DPS 重磅发布
    11月5日,在2022杭州 · 云栖大会上,数字化安全生产平台DPS重磅发布,助力传统运维向SRE转型。阿里巴巴资深技术专家 周洋十四五规划下,各行各业全面加速数字化转......
  • WordPress编辑器支持Word图片自动粘贴
    ​ 百度ueditor新增的将word内容导入到富文本编辑框的功能怎么没有啊,...ueditor实现word文档的导入和下载功能的方法:1、UEditor没有提供word的导入功能,只能说是粘贴复......
  • WordPress编辑器支持PowerPoint粘贴
    ​如何做到ueditor批量上传word图片?1、前端引用代码<!DOCTYPE html PUBLIC "-//W3C//DTDXHTML1.0Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-......
  • WordPress编辑器支持PowerPoint导入
    ​图片的复制无非有两种方法,一种是图片直接上传到服务器,另外一种转换成二进制流的base64码目前限chrome浏览器使用首先以um-editor的二进制流保存为例:打开umeditor.js,......