首页 > 其他分享 >230909 NOIP 模拟赛 T1 cake 题解

230909 NOIP 模拟赛 T1 cake 题解

时间:2023-09-11 12:57:48浏览次数:39  
标签:le 17 NOIP int 题解 230909 然后 状压 dp

原题

题意

有一块 \(n\times m\) \((1\le n,m\le 14)\) 的蛋糕,每个位置上有一个权值 \(a_{i,j}\) \((1\le a_{i,j}\le 1000)\),现在你要把它切开。每次你可以平行与某一边界把蛋糕切开,所以共有 \(n-1\) 个可以竖着切的位置,以及 \(m-1\) 个可以横着切的位置。

对于每一组 \(i,j\) \((0\le i\lt n,0\le j\lt m)\) ,你需要求得某种切割方案使得切完后每一块蛋糕的权值之和的最小值最大,输出这些最大值。


首先来个二维前缀和,然后我们来考虑具体做法。

数据范围一眼状压。那么久先考虑一个最暴力的状压做法,就是暴力枚举横着切的状态和竖着切的状态,然后计算答案。

光是枚举就 \(O(2^{n+m}nm)\) 了,不说了。

然后考虑到是对每一组 \(i,j\) 求解,所以考虑舍弃掉每次都重新算,就用 \(dp\) 的方式转移,然后我们来考虑把上面那东西变成 \(dp\) 的形式。

然后你就会发现把两维都状压真的很逆天,因为你在转移的时候计算贡献要用到的信息其实只有,就是,假如我们先只考虑一维,每次你切下一刀,转移的时候其实只关心上一刀切在哪里,然后中间多出来的那一堆和这一刀后面那一堆是需要计算的贡献,所以就是说你只需要知道上一刀切在哪里就可以了。

那么就有一个经典的 \(dp\):设 \(dp_{i,j}\) 表示第 \(i\) 刀切在位置 \(j\) 的答案。

然后就可以发现如上述计算贡献的时候,你还需要知道另一维是怎么分割的,所以可以加一维状压。

总的就是 \(dp_{i,j,k}\) 表示当横着的分割状态为 \(i\) 的时候,竖着的第 \(j\) 刀切在位置 \(k\) 的答案。

然后呢可以发现这题的的数据范围的话,对于状态 \(i\),即使不进行转移,也就是一个一个单独地算,也是完全能过的,所以直接枚举 \(i\) 就好了,不用把它加进 \(dp\)。

\(dp\) 部分转移的时候枚举上一刀切在哪里就好了,复杂度是 \(O(n^4)\)。稍微预处理一下就是 \(O(n^3)\)。但是枚举的时候很多地方跑不满,所以吸氧之后两种复杂度都跑得飞快(

总的时间复杂度就是 \(O(2^nn^3)\)。


总结

这题的过程大概就是,先考虑暴力,然后注意到题目的问题是要对每一组 \(i,j\) 求解,所以考虑通过转移的方式快速计算,而不是一个一个地单独计算,那么我们就考虑每次切一刀会对答案造成怎样的影响,然后就发现这个时候又要考虑横着的状态又要考虑竖着的状态,很难受啊,看一眼数据范围,那就状压吧,但是横着和竖着都状压很窒息啊,然后就思考每次切一刀然后计算贡献的时候需要的信息到底有哪些,然后就能发现当竖着的状态钦定好以后,横着切一刀的话只需要知道上一刀在哪里,然后就有了那个 \(dp\)。感觉思路是比较好的。

\(Code:\)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define il inline
#define re register
const int N=15;
int n,m,a[17][17],s[17][17],dp[N][N],U;
int ans[17][17],suf[N];
#define pb push_back
vector<int>v;
il int read(){
    re int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}
il int Sum(int x1,int y1,int x2,int y2){
    return s[x2][y2]-s[x2][y1-1]-s[x1-1][y2]+s[x1-1][y1-1];
}
il bool ex(int i,int j){
    return ((i>>(j-1))&1);
}
int main(){
//	freopen("cake3.in","r",stdin);
//	freopen("cake3.out","w",stdout);
    n=read(),m=read();
    U=1<<(n-1);
    for(re int i=1;i<=n;i++)
        for(re int j=1;j<=m;j++)a[i][j]=read();
    for(re int i=1;i<=n;i++)
        for(re int j=1;j<=m;j++)
            s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];
    for(re int i=0;i<U;i++){
        v.clear();
        v.pb(0);
        for(re int j=1;j<n;j++)
            if(ex(i,j))v.pb(j);
        v.pb(n);
        int siz=v.size();
        for(re int j=0;j<=m;j++)
            for(re int k=0;k<=m;k++)dp[j][k]=0;
        for(re int j=0;j<m;j++){
            int res=1e9;
            for(re int k=1;k<siz;k++)
                res=min(res,Sum(v[k-1]+1,j+1,v[k],m));
            suf[j]=res;
        }
        dp[0][0]=suf[0];
        int cnti=__builtin_popcount(i);
        ans[cnti][0]=max(ans[cnti][0],dp[0][0]);
        for(re int now=1;now<m;now++)
        	for(re int pst=0;pst<now;pst++){
                int res=1e9;
                for(re int k=1;k<siz;k++)res=min(res,Sum(v[k-1]+1,pst+1,v[k],now));
                for(re int cnt=1;cnt<=now;cnt++){
                	dp[now][cnt]=max(dp[now][cnt],min(dp[pst][cnt-1],min(res,suf[now])));
                	ans[cnti][cnt]=max(ans[cnti][cnt],dp[now][cnt]);
            	}
            }
    }
    for(re int i=0;i<n;i++,putchar('\n'))
        for(re int j=0;j<m;j++)printf("%d ",ans[i][j]);
    return 0;
}

标签:le,17,NOIP,int,题解,230909,然后,状压,dp
From: https://www.cnblogs.com/MrcFrst-LRY/p/17693204.html

相关文章

  • 【题解】Educational Codeforces Round 142(CF1792)
    没有手速,再加上被E卡了,废掉了。A.GamingForces题目描述:Monocarp正在玩电脑游戏。他打算杀死\(n\)个怪兽,第\(i\)个的血量为\(h_i\)。Monocarp的角色有两个魔法咒语如下,都可以以任意顺序用任意次(可以不用),每次使用相当于一次操作。选择两个怪兽并各扣一滴血。选择......
  • win更新后出现强制同意跨境传输数据问题解决方案
    总体来说就是删除那个更新-  KB5028166解决方法如下:一、在同意个人数据跨境传输界面按ctrl+alt+,进入任务管理器二、按住shift键, 点击右下角关机按钮选择重启三、在弹出的界面选择疑难解答,高级选项四、卸载更新-卸载最新质量更新,卸载完成,重启电脑决这个问题......
  • 题解 LOJ6738【王的象棋世界】
    problem一个\(R\timesC\)的棋盘,你有\(Q\)组询问,每次询问国王走\(R-1\)步从\((1,a)\)到达\((R,b)\)有多少种方案。你只需要输出答案对\(998244353\)取模的结果。\(2\leC\le10^5,C\leR\le10^9,1\leQ\le10^5\)。solution首先DP和矩阵优化DP都比较简单,但......
  • CSP-S2022初赛易错题解析
    一.2.错误原因:不会解析:real代表实际运行时间,user代表用户态运行时间,sys表示内核态运行时间,故选A 5.错误原因:不会解析:基数排序的思路类似于桶排序,故选A 9.错误原因:不会解析:这个问题可以转化成圆排列问题,公式为A(n-1,n-1),即(n-1)!,要考虑从两个方向看的图,所以要除......
  • 网络规划设计师真题解析--IP地址(七)
    DHCP服务器分配的默认网关地址是220.115.5.33/28,()是该子网主机地址。(2015年真题)A.220.115.5.32    B.220.115.5.40C.220.115.5.47    D.220.115.5.55答案:B解析:220.115.5.33/28建网比特数/28,只看第四位220.115.5.3300100001220.115.5.3200100000(主机位全零......
  • 【题解】CF1830E Bully Sort
    考虑一次交换,我们发现,被选出来的\([i,j]\)的区间里\(p_i\)一定是最大的,\(p_j\)一定是最小的。然后我们会发现,我们原序列的逆序对数量会减少\(2(j-i)-1\),而\(\sum|p_i-i|\)会减少\(2(j-i)\)那么答案就是原序列的两部分相减(神奇的性质又增加了!)。至于我们的后半部分显......
  • CF题解合集
    CF比赛题解合集\(\downarrow2023.09.04\)CF1952,CF19541952A.Ntarsis'Set有一个集合,初始状态里面有数字\(1\)、\(2\)、\(3\)、\(4\)、\(5\)、......、\(10^{1000}\)。现在给你一个长度为\(n\)数组\(a(1\leqa_i\leq10^9)\),要进行\(k\)次操作,每次操作将当前......
  • 【题解】CF1830B The BOSS Can Count Pairs
    你考虑,我们观察数据范围,发现可以是\(O(n\sqrtn)/O(n\logn)\)的,我们又看到乘法,便有几个大概的想法:数论分块\(O(\sqrtn)\)枚举其中一个乘数还有什么……(笔者学识浅陋,读者可以帮忙补充)我们可以找到两种\(O(n^2)\)做法:\(O(n^2)\)枚举数对\((i,j)\)然后进行判断。......
  • 【题解】[ABC318F] Octopus(思维)
    【题解】[ABC318F]Octopus题目链接F-Octopus题意概述有个机器人,它有\(n\)个手臂,第\(i\)个手臂长度为\(l_i\)。同时有\(n\)个宝藏,第\(i\)个宝藏的坐标是\(x_i\)。当机器人位于\(k\)时,它的第\(i\)条手臂可以够到\([k-l_i,k+l_i]\)范围内的宝藏。机器人的每......
  • [ABC319D] Minimum Width 题解
    [ABC319D]MinimumWidth题解题意分析  给定\(n\)个单词,现在想像“记事本”一样把它们依次地一行一行显示出来。每个字母宽度为一,单词之间需要有空格,宽度也为一。一个单词不可以成两部分显示在两行。如果单词最后一个字母来到行末,直接换行,不用空格。  给定窗口最大高度......