$CH5104\ I-country$ 线性$DP$

CH

 

Sol

”凸联通块“是什么意思呢?

其实就是图形的左端点先减小再增大,右端点先增大再减小

阶段

考虑到第k行,已经选了i个格子

状态

1.第i行的左端点与右端点

2.这一行的左端点相对于上一行的左端点是递增还是递减

这一行的右端点相对于上一行的右端点是递增还是递减

所以,f[k][i][l][r][0/1][0/1]表示考虑完第k行,已经选了i个格子,这一行的左端点是l,右端点是r,左端点相对于上一行递增(0)/递减(1),这一行的右端点.......

转移

考虑p,q的范围以及通过上一行的四种状态的哪种转移而来

有这么四种情况:(p,q为枚举的上一行的左右端点)

1.左减右增

l<=p<=q<=r<=m 通过f[k][i][p][q][1][0]转移

2.左增右增

1<=p<=l<=q<=r<=m 通过f[k][i][p][q][0/1][0]转移

3.左减右减

l<=p<=r<=q<=m 通过f[k][i][p][q][1][0/1]转移

4.左增右减

1<=p<=l<=r<=q<=m 通过f[k][i][p][q][0/1][0/1]转移

 

Code

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define Rg register
 5 #define il inline
 6 #define go(i,a,b) for(Rg int i=a;i<=b;i++)
 7 using namespace std;
 8 int ans,n,m,K,ak,ai,al,ar,ax,ay,c[16][16],f[16][226][16][16][2][2];
 9 struct node{int l,r,x,y;}a[16][226][16][16][2][2];
10 il void print(int k,int i,int l,int r,int x,int y)
11 {
12     if(!k || !i)return;
13     print(k-1,i-(r-l+1),a[k][i][l][r][x][y].l,a[k][i][l][r][x][y].r,a[k][i][l][r][x][y].x,a[k][i][l][r][x][y].y);
14     go(t,l,r)printf("%d %d\n",k,t);
15 }
16 int main()
17 {
18     freopen("CH5104.out","w",stdout);
19     scanf("%d%d%d",&n,&m,&K);
20     go(i,1,n)go(j,1,m)scanf("%d",&c[i][j]),c[i][j]+=c[i][j-1];
21     go(k,1,n)
22         go(i,1,K)
23         go(l,1,m)
24         go(r,l,m)
25     {
26         int sm=c[k][r]-c[k][l-1],t=r-l+1;
27         if(i<t)break;
28         //1,0 zuojian youzen
29             go(p,l,r)go(q,p,r)
30                 if(f[k][i][l][r][1][0]<sm+f[k-1][i-t][p][q][1][0])
31                     f[k][i][l][r][1][0]=sm+f[k-1][i-t][p][q][1][0],a[k][i][l][r][1][0]=(node){p,q,1,0};
32         //1,1 zuojian youjian
33         go(p,l,r)go(q,r,m)go(y,0,1)
34             if(f[k][i][l][r][1][1]<sm+f[k-1][i-t][p][q][1][y])
35                 f[k][i][l][r][1][1]=sm+f[k-1][i-t][p][q][1][y],a[k][i][l][r][1][1]=(node){p,q,1,y};
36         //0,1 zuozen youjian
37         go(p,1,l)go(q,r,m)go(x,0,1)go(y,0,1)
38             if(f[k][i][l][r][0][1]<sm+f[k-1][i-t][p][q][x][y])
39                 f[k][i][l][r][0][1]=sm+f[k-1][i-t][p][q][x][y],a[k][i][l][r][0][1]=(node){p,q,x,y};
40         //0,0 zuozen youzen
41         go(p,1,l)go(q,l,r)go(x,0,1)
42             if(f[k][i][l][r][0][0]<sm+f[k-1][i-t][p][q][x][0])
43                 f[k][i][l][r][0][0]=sm+f[k-1][i-t][p][q][x][0],a[k][i][l][r][0][0]=(node){p,q,x,0};
44         if(i!=K)continue;
45         go(x,0,1)go(y,0,1)
46             if(ans<f[k][i][l][r][x][y]){ans=f[k][i][l][r][x][y];ak=k;ai=i;al=l;ar=r;ax=x;ay=y;}
47     }
48     printf("Oil : %d\n",ans);
49     print(ak,ai,al,ar,ax,ay);
50     return 0;
51 }
View Code

 

转载于:https://www.cnblogs.com/forward777/p/10998749.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值