当前位置: 首页 > article >正文

题解:P10972 I-Country

题目传送门

思路

因为占据的连通块的左端点先递减、后递增,右端点先递增、后递减,所以设 f i , j , l , r , x ( 0 / 1 ) , y ( 0 / 1 ) f_{i,j,l,r,x(0/1),y(0/1)} fi,j,l,r,x(0/1),y(0/1) 为前 i i i 行中,选择 j j j 个方格,其中第 i i i 行选择的区间的左端点为 l l l,右端点为 r r r x x x 表示左端点是否出现递增, y y y 表示右端点是否递增的所有方案的最大石油数量。

容易列出状态转移方程,
f i , j , l , r , 0 , 0 = max ⁡ { f i − 1 , j − ( r − l + 1 ) , a , b , 0 , 0 , f i − 1 , j − ( r − l + 1 ) , a , b , 0 , 1 } + s i , r − s i , l − 1 f i , j , l , r , 0 , 1 = max ⁡ { f i − 1 , j − ( r − l + 1 ) , a , b , 0 , 1 } + s i , r − s i , l − 1 f i , j , l , r , 1 , 0 = max ⁡ { f i − 1 , j − ( r − l + 1 ) , a , b , 0 , 0 , f i − 1 , j − ( r − l + 1 ) , a , b , 0 , 1 , f i − 1 , j − ( r − l + 1 ) , a , b , 1 , 0 , f i − 1 , j − ( r − l + 1 ) , a , b , 1 , 1 } + s i , r − s i , l − 1 f i , j , l , r , 1 , 1 = max ⁡ { f i − 1 , j − ( r − l + 1 ) , a , b , 0 , 1 , f i − 1 , j − ( r − l + 1 ) , a , b , 1 , 1 } + s i , r − s i , l − 1 f_{i,j,l,r,0,0}=\max\{f_{i-1,j-(r-l+1),a,b,0,0},f_{i-1,j-(r-l+1),a,b,0,1}\}+s_{i,r}-s_{i,l-1}\\ f_{i,j,l,r,0,1}=\max\{f_{i-1,j-(r-l+1),a,b,0,1}\}+s_{i,r}-s_{i,l-1}\\ f_{i,j,l,r,1,0}=\max\{f_{i-1,j-(r-l+1),a,b,0,0},f_{i-1,j-(r-l+1),a,b,0,1},f_{i-1,j-(r-l+1),a,b,1,0},f_{i-1,j-(r-l+1),a,b,1,1}\}+s_{i,r}-s_{i,l-1}\\ f_{i,j,l,r,1,1}=\max\{f_{i-1,j-(r-l+1),a,b,0,1},f_{i-1,j-(r-l+1),a,b,1,1}\}+s_{i,r}-s_{i,l-1}\\ fi,j,l,r,0,0=max{fi1,j(rl+1),a,b,0,0,fi1,j(rl+1),a,b,0,1}+si,rsi,l1fi,j,l,r,0,1=max{fi1,j(rl+1),a,b,0,1}+si,rsi,l1fi,j,l,r,1,0=max{fi1,j(rl+1),a,b,0,0,fi1,j(rl+1),a,b,0,1,fi1,j(rl+1),a,b,1,0,fi1,j(rl+1),a,b,1,1}+si,rsi,l1fi,j,l,r,1,1=max{fi1,j(rl+1),a,b,0,1,fi1,j(rl+1),a,b,1,1}+si,rsi,l1

注意,由于联通,所以 r ≥ a r\ge a ra l ≤ b l\le b lb。因为递增递减,所以当 x = 0 x=0 x=0 时, l ≤ a l\le a la,当 x = 1 x=1 x=1 时, l ≥ a l\ge a la,当 y = 0 y=0 y=0 时, r ≤ b r\le b rb,当 y = 1 y=1 y=1 时, r ≥ b r\ge b rb s i , j s_{i,j} si,j 为第 i i i 行的前缀和,不是二维前缀和。

最终答案为 max ⁡ { f i , k , l , r , x , y } \max\{f_{i,k,l,r,x,y}\} max{fi,k,l,r,x,y},输出路径可以存一个结构体 l a i , j , l , r , x , y la_{i,j,l,r,x,y} lai,j,l,r,x,y 统计 f i , j , l , r , x , y f_{i,j,l,r,x,y} fi,j,l,r,x,y 从哪里转移来。

思路容易想,代码细节却很多,本人被硬控了几个小时

代码

//要C++14(GCC 9),不然会RE
#include <bits/stdc++.h>
using namespace std;
const int N=25;
struct Last{
    int i,j,l,r,x,y;
}la[N][N*N][N][N][2][2];
int n,m,k,a[N][N],s[N][N],f[N][N*N][N][N][2][2];
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            scanf("%d",&a[i][j]);
            s[i][j]=s[i][j-1]+a[i][j];
        }

    for(int i=1;i<=n;i++)
        for(int j=1;j<=i*m;j++)
            for(int l=1;l<=m;l++)
                for(int r=l;r<=m;r++){
                    if(r-l+1+(i-1)*m<j || j<r-l+1)
                        continue;
                    int sum=s[i][r]-s[i][l-1];
                    if(i==1){
                        f[i][j][l][r][0][0]=f[i][j][l][r][0][1]=f[i][j][l][r][1][0]=f[i][j][l][r][1][1]=sum;
                        continue;
                    }
                    //x=0,y=0
                    for(int x=1;x<=m;x++)
                        for(int y=x;y<=m;y++)
                            if(!(y<l || x>r) && x>=l && y>=r){//注意要联通,l要递减,r要递减
                                if(f[i-1][j-(r-l+1)][x][y][0][0]+sum>f[i][j][l][r][0][0])
                                    f[i][j][l][r][0][0]=f[i-1][j-(r-l+1)][x][y][0][0]+sum,la[i][j][l][r][0][0]={i-1,j-(r-l+1),x,y,0,0};

                                if(f[i-1][j-(r-l+1)][x][y][0][1]+sum>f[i][j][l][r][0][0])
                                    f[i][j][l][r][0][0]=f[i-1][j-(r-l+1)][x][y][0][1]+sum,la[i][j][l][r][0][0]={i-1,j-(r-l+1),x,y,0,1};
                            }
                    //x=0,y=1
                    for(int x=1;x<=m;x++)
                        for(int y=x;y<=m;y++)
                            if(!(y<l || x>r) && x>=l && y<=r){//l要递减,r要递增
                                if(f[i-1][j-(r-l+1)][x][y][0][1]+sum>f[i][j][l][r][0][1])
                                    f[i][j][l][r][0][1]=f[i-1][j-(r-l+1)][x][y][0][1]+sum,la[i][j][l][r][0][1]={i-1,j-(r-l+1),x,y,0,1};
                            }
                    //x=1,y=0
                    for(int x=1;x<=m;x++)
                        for(int y=x;y<=m;y++)
                            if(!(y<l || x>r) && x<=l && y>=r){//l要递增,r要递减
                                if(f[i-1][j-(r-l+1)][x][y][0][0]+sum>f[i][j][l][r][1][0])
                                    f[i][j][l][r][1][0]=f[i-1][j-(r-l+1)][x][y][0][0]+sum,la[i][j][l][r][1][0]={i-1,j-(r-l+1),x,y,0,0};

                                if(f[i-1][j-(r-l+1)][x][y][0][1]+sum>f[i][j][l][r][1][0])
                                    f[i][j][l][r][1][0]=f[i-1][j-(r-l+1)][x][y][0][1]+sum,la[i][j][l][r][1][0]={i-1,j-(r-l+1),x,y,0,1};

                                if(f[i-1][j-(r-l+1)][x][y][1][0]+sum>f[i][j][l][r][1][0])
                                    f[i][j][l][r][1][0]=f[i-1][j-(r-l+1)][x][y][1][0]+sum,la[i][j][l][r][1][0]={i-1,j-(r-l+1),x,y,1,0};

                                if(f[i-1][j-(r-l+1)][x][y][1][1]+sum>f[i][j][l][r][1][0])
                                    f[i][j][l][r][1][0]=f[i-1][j-(r-l+1)][x][y][1][1]+sum,la[i][j][l][r][1][0]={i-1,j-(r-l+1),x,y,1,1};
                            }
                    //x=1,y=1
                    for(int x=1;x<=m;x++)
                        for(int y=x;y<=m;y++)
                            if(!(y<l || x>r) && x<=l && y<=r){//l要递增,r要递增
                                if(f[i-1][j-(r-l+1)][x][y][0][1]+sum>f[i][j][l][r][1][1])
                                    f[i][j][l][r][1][1]=f[i-1][j-(r-l+1)][x][y][0][1]+sum,la[i][j][l][r][1][1]={i-1,j-(r-l+1),x,y,0,1};

                                if(f[i-1][j-(r-l+1)][x][y][1][1]+sum>f[i][j][l][r][1][1])
                                    f[i][j][l][r][1][1]=f[i-1][j-(r-l+1)][x][y][1][1]+sum,la[i][j][l][r][1][1]={i-1,j-(r-l+1),x,y,1,1};
                            }
                }

    int ans=0;
    Last tmp;
    for(int i=1;i<=n;i++)
        for(int l=1;l<=m;l++)
            for(int r=l;r<=m;r++){
                if(f[i][k][l][r][0][0]>ans)
                    ans=f[i][k][l][r][0][0],tmp={i,k,l,r,0,0};//tmp存储当前的状态

                if(f[i][k][l][r][0][1]>ans)
                    ans=f[i][k][l][r][0][1],tmp={i,k,l,r,0,1};

                if(f[i][k][l][r][1][0]>ans)
                    ans=f[i][k][l][r][1][0],tmp={i,k,l,r,1,0};

                if(f[i][k][l][r][1][1]>ans)
                    ans=f[i][k][l][r][1][1],tmp={i,k,l,r,1,1};
            }
    printf("Oil : %d",ans);
    while(tmp.j && tmp.i){//输出路径
        for(int i=tmp.l;i<=tmp.r;i++)
            printf("\n%d %d",tmp.i,i);
        tmp=la[tmp.i][tmp.j][tmp.l][tmp.r][tmp.x][tmp.y];
    }
    return 0;
}

http://www.kler.cn/a/524212.html

相关文章:

  • NoSQL与SQL比较
  • 【C++ 真题】P1706 全排列问题
  • mybatis(112/134)
  • 【Elasticsearch】Elasticsearch的查询
  • SuperAGI - 构建、管理和运行 AI Agent
  • [EAI-023] FAST: Efficient Action Tokenization for Vision-Language-Action Models
  • Swift 中 Codable 和 Hashable 的理解
  • < OS 有关> BaiduPCS-Go 程序的 菜单脚本 Script: BaiduPCS-Go.Menu.sh (bdgo.sh)
  • 基于 STM32 的智能工业水质监测与净化系统
  • scrol家族 offset家族 client家族学习
  • js学习笔记(2)
  • 单链表专题(上)
  • 玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
  • 19.Word:小马-校园科技文化节❗【36】
  • QT+mysql+python 效果:
  • 八种排序算法【C语言实现】
  • 代码随想录| 动态规划188.买卖股票的最佳时机IV 309.最佳买卖股票时机含冷冻期 714.买卖股票的最佳时机含手续费
  • 技术发展视域下中西方技术研发思维方式的比较与启示
  • 传奇引擎游戏微端的作用
  • 5分钟带你获取deepseek api并搭建简易问答应用
  • AI工具灵感速递:离线ChatGPT×自然语言全栈开发×智能文件重命名,开发者效率革命!
  • DeepSeek-R1:开源Top推理模型的实现细节、使用与复现
  • 【华为OD-E卷 - 字符串解密 100分(python、java、c++、js、c)】
  • 52. TCP四次挥手
  • 动态规划<九>两个数组的dp
  • 基于SpringBoot电脑组装系统平台系统功能实现六