首页 > 其他分享 >P1398 [NOI2013] 书法家

P1398 [NOI2013] 书法家

时间:2024-07-31 11:40:49浏览次数:6  
标签:书法家 P1398 limits max ll NOI2013 cases dp define

思路:

来一篇极小常数的 \(O(N^3M)\) 和 \(O(N^2M \log^2 N)\) 的题解,最慢点在 500ms 以下但是为什么还是最劣解

定义 \(dp_{i,j,k,x \in \{0,1,2\},y \in \{0,1,2\}}\) 表示对于正在画的第 \(x\) 个字符,目前正在画开头/中间/结尾,且当前画的矩形的右下角是 \((i,j)\) 和右上角 \((k,j)\)。

则状态转移方程为,为了使式子不过于太丑陋,分段函数就表示取 \(\max\):

\[dp_{i,j,k,0,0} = \begin{cases} \sum\limits_{I=k}^i a_{I,j} \\ \sum\limits_{I=k}^i a_{I,j} + dp_{i,j-1,k} \end{cases} \]

\[dp_{i,j,k,0,1} = \sum\limits_{I=k}^i a_{I,j} + \begin{cases} \max\limits_{l=i+1}^n dp_{l,j-1,k,0,0} \\ \max\limits_{x=k}^i \max\limits_{y=1}^k dp_{x,j-1,y,0,1} \\ \max\limits_{y=1}^{k-1} dp_{k-1,j-1,y} \end{cases} \]

\[dp_{i,j,k,0,2} = \sum\limits_{I=k}^i a_{I,j} + \begin{cases} \max\limits_{l=k+1}^i dp_{i,j-1,l,0,1} \\ dp_{i,j-1,k,0,2} \end{cases} \]

\[dp_{i,j,k,1,0} = \sum\limits_{I=k}^i a_{I,j} + \max\limits_{x=1}^n \max\limits_{z=1}^{k-2} \max\limits_{y=1}^i dp_{i,z,y,0,2} \]

\[dp_{i,j,k,1,1} = a_{k,j} + a_{i,j} + \begin{cases} dp_{i,j-1,k,1,0} \\ dp_{i,j-1,k,1,1} \end{cases} \]

\[dp_{i,j,k,1,2} = \sum\limits_{I=k}^i a_{I,j} + dp_{i,j-1,k,1,1} \]

\[dp_{i,j,k,2,0} = a_{k,j} + a_{i,j} + \begin{cases} dp_{i,j-1,k,2,0} \\ \max\limits_{x=1}^n \max\limits_{z=1}^{k-2} \max\limits_{y=1}^i dp_{i,z,y,1,2} \end{cases} \]

\[dp_{i,j,k,2,1} = \sum\limits_{I=k}^i a_{I,j} + \begin{cases} dp_{i,j-1,k,2,0} \\ dp_{i,j-1,k,2,1}\end{cases} \]

\[dp_{i,j,k,2,2} = a_{k,j} + a_{i,j} + \begin{cases} dp_{i,j-1,k,2,1} \\ dp_{i,j-1,k,2,2} \end{cases} \]

对于一重循环部分,可以直接前缀/后缀预处理 \(\max\);对于查询矩阵最大值部分,可以用二维 ST 表或者暴力扫一维然后预处理另外一维的前缀/后缀 \(\max\)。

时间复杂度为 \(O(N^3M)\) 或 \(O(N^2M \log^2 N)\),由于感觉二维 ST 表可能快不了多少,于是没有写,有兴趣的读者可以自己尝试一下。

空间可能开不下,要用滚动数组优化。

完整代码:

#include<bits/stdc++.h>
#define Add(x,y) (x+y>=mod)?(x+y-mod):(x+y)
#define lowbit(x) x&(-x)
#define pi pair<ll,ll>
#define pii pair<ll,pair<ll,ll>>
#define iip pair<pair<ll,ll>,ll>
#define ppii pair<pair<ll,ll>,pair<ll,ll>>
#define fi first
#define se second
#define full(l,r,x) for(auto it=l;it!=r;it++) (*it)=x
#define Full(a) memset(a,0,sizeof(a))
#define open(s1,s2) freopen(s1,"r",stdin),freopen(s2,"w",stdout);
using namespace std;
typedef double db;
typedef unsigned long long ull;
typedef int ll;
bool Begin;
const ll N=155,M=505,INF=1e9; 
inline ll read(){
    ll 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<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x*f;
}
inline void write(ll x){
	if(x<0){
		putchar('-');
		x=-x;
	}
	if(x>9)
	  write(x/10);
	putchar(x%10+'0');
}
ll n,m,ans=-INF;
ll a[N][M],s[N][M];
ll dp[2][N][M][N];
ll MAX[M][2],T1[N][M],T2[N][M][N],T3[N][M][N],T4[N][M][N];
bool End;
int main(){
//	open("A.in","A.out");
	memset(T1,-0x7f,sizeof(T1));
	memset(T2,-0x7f,sizeof(T2));
	memset(T3,-0x7f,sizeof(T3));
	memset(T4,-0x7f,sizeof(T4));
	memset(MAX,-0x7f,sizeof(MAX));
	memset(dp,-0x7f,sizeof(dp));
	n=read(),m=read();
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=m;j++)
		a[i][j]=read();
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=m;j++)
		s[i][j]=s[i-1][j]+a[i][j];
	for(int i=1;i<=n;i++)
	  for(int j=1;j<=m;j++)
		for(int k=1;k<=i-1;k++)
		  dp[0][i][j][k]=s[i][j]-s[k-1][j]+max(dp[0][i][j-1][k],0);
	for(int j=1;j<=m;j++){
	    for(int i=n;i>=1;i--){
	    	for(int k=1;k<=i;k++){
	    		dp[1][i][j][k]=max(T1[k-1][j-1],T2[i+1][j-1][k]);
		    	for(int x=k;x<=i;x++)
		    	  dp[1][i][j][k]=max(dp[1][i][j][k],T3[x][j-1][k]);
		    	dp[1][i][j][k]+=s[i][j]-s[k-1][j];  
		    	T1[i][j]=max(T1[i][j],dp[1][i][j][k]);
		    	T2[i][j][k]=max(T2[i+1][j][k],dp[0][i][j][k]);
		    	T3[i][j][k]=max(T3[i][j][k-1],dp[1][i][j][k]);
			}
		}
	}
	memset(dp[0],-0x7f,sizeof(dp[0]));
	for(int j=1;j<=m;j++){
	    for(int i=1;i<=n;i++){
	    	ll M=-INF;
	    	for(int k=i-1;k>=1;k--){
	    		M=max(M,dp[1][i][j-1][k+1]);
	    		dp[0][i][j][k]=M;
			    dp[0][i][j][k]=max(dp[0][i][j][k],dp[0][i][j-1][k]);
			    dp[0][i][j][k]+=s[i][j]-s[k-1][j];
			    MAX[j][0]=max({MAX[j][0],MAX[j-1][0],dp[0][i][j][k]});
			}
		}
	}
	memset(dp[1],-0x7f,sizeof(dp[1]));
	for(int j=5;j<=m;j++)
	  for(int i=1;i<=n;i++)  
	    for(int k=1;k<=i-2;k++)
	      dp[1][i][j][k]=s[i][j]-s[k-1][j]+MAX[j-2][0];
	memset(dp[0],-0x7f,sizeof(dp[0]));
	for(int j=6;j<=m;j++)
	  for(int i=1;i<=n;i++)
	    for(int k=1;k<=i-2;k++)
	      dp[0][i][j][k]=a[k][j]+a[i][j]+max(dp[1][i][j-1][k],dp[0][i][j-1][k]);
	memset(dp[1],-0x7f,sizeof(dp[1]));
	for(int j=7;j<=m;j++){
	    for(int i=1;i<=n;i++){
		    for(int k=1;k<=i-2;k++){
		    	dp[1][i][j][k]=s[i][j]-s[k-1][j]+dp[0][i][j-1][k];	
		    	MAX[j][1]=max({MAX[j][1],MAX[j-1][1],dp[1][i][j][k]});
			} 
		}
	}
	memset(dp[0],-0x7f,sizeof(dp[0]));
	for(int j=9;j<=m;j++)
	  for(int i=1;i<=n;i++)
		for(int k=1;k<=i-2;k++)
		  dp[0][i][j][k]=a[k][j]+a[i][j]+max(dp[0][i][j-1][k],MAX[j-2][1]);
	memset(dp[1],-0x7f,sizeof(dp[1]));
	for(int j=10;j<=m;j++)
	  for(int i=1;i<=n;i++)
		for(int k=1;k<=i-2;k++)
		  dp[1][i][j][k]=s[i][j]-s[k-1][j]+max(dp[0][i][j-1][k],dp[1][i][j-1][k]);
	memset(dp[0],-0x7f,sizeof(dp[0]));
	for(int j=11;j<=m;j++){
	    for(int i=1;i<=n;i++){
		    for(int k=1;k<=i-2;k++){
		    	dp[0][i][j][k]=a[k][j]+a[i][j]+max(dp[1][i][j-1][k],dp[0][i][j-1][k]);
		    	ans=max(ans,dp[0][i][j][k]);
			}
		}
	}
	write(ans);
	cerr<<'\n'<<abs(&Begin-&End)/1048576<<"MB";
	return 0;
}

标签:书法家,P1398,limits,max,ll,NOI2013,cases,dp,define
From: https://www.cnblogs.com/rgw2010/p/18333500

相关文章

  • G73 线段树+线性基合并 P5607 [Ynoi2013] 无力回天 NOI2017
    视频链接:G73线段树+线性基合并P5607[Ynoi2013]无力回天NOI2017_哔哩哔哩_bilibili   P5607[Ynoi2013]无力回天NOI2017-洛谷|计算机科学教育新生态(luogu.com.cn)//线段树+线性基合并O(n*logn*logv*logv)#include<iostream>#include<cstring>#incl......
  • P5610 [Ynoi2013] 大学
    [Ynoi2013]大学-洛谷傻逼卡常题发现自己基础数据结构用的还不是很熟练,并没有想到一开始的\(set\)做法,更不用提后面的并查集优化了首先每个数最多被进行\(O(\logA)\)次有效除法,如果我们找到区间中哪些数要被除后直接暴力用树状数组单点修改,可以做到\(O(n\logn......
  • P5607 [Ynoi2013] 无力回天 NOI2017
    [Ynoi2013]无力回天NOI2017-洛谷看到题目可以想到线性基线性基可以做到\(O(\logA)\)加入,\(O(\logA)\)查询,\(O(\log^2A)\)合并考虑直接暴力的用线段树维护每个节点的线性基,可以做到\(O(n\logn\log^2A)\)但有区间修改?差分转单点修,发现线性基\(a_{[l......
  • [Ynoi2013] 大学
    非常好之\(\texttt{lxl}\)使我的代码旋转。看到这个题,第一反应显然是如果我们能够每次确切的找到要除的数,然后用树状数组进行单点修改,那么就可以达到\(\mathcal{O}(n\logV\logn)\)的复杂度。那么接下来就是考虑如何去找到能除的数。首先,我们不难想到对于每个权值\(v\)......
  • P5609 [Ynoi2013] 对数据结构的爱
    题面传送门好像搞了个神秘做法。考虑离线扫描线,用一个fhq-Treap维护所有的询问现在长什么样,然后每次操作就整体加\(A_i\),\(\geqp\)的减去\(p\),这个可以分裂之后打整体标记,然后用那个值域相交的fhq-Treap合并实现。然后你发现这样就过了。构造一下卡不掉,于是考虑给这个......
  • P3227 [HNOI2013] 切糕
    题意linkSol考虑不戴限制的情况,那就是对于每一层连到下一层跑网络流。考虑戴上添边,不难发现向相邻的点连一条\(inf\)边就行了。Code#include<iostream>#include<algorithm>#include<cstdio>#include<array>#include<queue>#defineintlonglong#definepiipa......
  • P1232 [NOI2013] 树的计数
    首先要明确,对于一个结点,其儿子的遍历顺序是确定的,在DFS序和BFS序中相同。而BFS序更容易确定一棵树的深度,只需要知道在哪些结点分了层。所以可以通过DFS序来确定BFS中的分层方案。然后分类讨论:\(BFS_u+1=BFS_v\),\(DFS_u>DFS_v\),相差恰好一层。若同层则说明DFS先进......
  • P3227 [HNOI2013]切糕
    P3227[HNOI2013]切糕题意给定一个\(P\timesQ\)的平面,平面上每一个点上都有一个高度为\(R\)的竖条。竖条上每一个点都有一个不和谐度\(f(x,y,z)\),对于每一个竖条选一个点,要求与周围的点的高度差不超过\(d\)(四联通),求最小不和谐度。题解感觉这道题很神啊,首先我们考......
  • [ [Ynoi2013] 无力回天 NOI2017 ] 解题报告
    [Ynoi2013]无力回天NOI2017首先看到异或,想到能维护异或的东西就那几样(线性基/01trie/数位dp/FWT),再看到求选任意个数后的异或最大值,线性基无疑了。这时再看还要维护什......
  • 【题解】[Ynoi2013] 大学
    题目分析:考虑对于一次修改至少会让\(x\)变成\(\frac{x}{2}\)所以对于每一个数最多被操作\(\log{n}\)次,那么直接暴力操作就好了。所以其实关键问题是每次怎么找到哪......