石门集训 8.16 题解

T4

T4-Relay Race

是个动规题,没反应过来啊,虽然大概率也不会。写了个 dfs。

题意

n×nn\times n 的矩形,价值为 ai,ja_{i,j}
现在你要从 a1,1a_{1,1} ,通过移动到 ai,j+1,ai+1,ja_{i,j+1},a_{i+1,j} 的方式,走到 an,na_{n,n}
再通过移动到 ai,j1,ai1,ja_{i,j-1},a_{i-1,j} 的方式,回去 a1,1a_{1,1}。定义价值为路径上 ai,ja_{i,j} 的和,重复走过的路径只计算一次。

问最大的价值是多少?


input

3
1 2 3
4 5 6
7 8 9

output

42

General Idea\Large\color{skyblue} General \ Idea

错解

首先,猜个结论:先从 1,11,1 跑 dp。然后按路径将 aia_i 设为 00。在从 an,na_{n,n} 跑 dp。

但是这样做是错误的。

3
5 5 1
0 5 -2
5 -4 -2

dp 会跑出来 11+111+1 的结果。但是正解却是 4+104+10

dp:

(1,1)(1,2)(2,2)(2,3)(3,3)(3,2)(3,1)(2,1)(1,1)(1,1)\to(1,2)\to(2,2)\to(2,3)\to(3,3)\to(3,2)\to(3,1)\to(2,1)\to(1,1)

5+5+522=11,04+5+0+0=15+5+5-2-2=11,0-4+5+0+0=1

正解:

(1,1)(2,1)(3,1)(3,2)(3,3)(3,2)(2,2)(2,1)(1.1)(1,1)\to(2,1)\to(3,1)\to(3,2)\to(3,3)\to(3,2)\to(2,2)\to(2,1)\to(1.1)

5+0+542=4,0+0+5+5+0=105+0+5-4-2=4,0+0+5+5+0=10


动态规划

此时我们就举出了反例。还是老实用朴素的 dp 吧。本题可以理解为有两个人从 (1,1)(1,1) 走到 (n,n)(n,n)。那就可以将状态设为 dpx,y,xx,yydp_{x,y,xx,yy}。分别是第一个人的坐标,第二个人的坐标。
我们使两个人一起走,如果两人坐标相同,就只算一遍。这个时候的状态转移方程即让两个人各走一步:

dpx,y,xx,yy=max{dpx1,y,xx1,yy,dpx1,y,xx,yy1,dpx,y1,xx1,yy,dpx,y1,xx,yy1}dp_{x,y,xx,yy}=\max\{dp_{x-1,y,xx-1,yy},dp_{x-1,y,xx,yy-1},dp_{x,y-1,xx-1,yy},dp_{x,y-1,xx,yy-1}\}

但是时空复杂度:Θ(n4)\Theta (n^4)

优化

考虑优化,dp 优化的本质就是削减无用状态与重复转移。我们注意到,只有 x+y=xx+yyx+y=xx+yy 的状态是有意义的,因为如果不同,说明不符合两个人一起走的定义。

假如两个人同时走,那么他们的坐标和就会相同。设坐标和为 ss。那么枚举 s,x,xxs,x,xxy,yyy,yy 就可以算出来了。此时可设 dps,x,xxdp_{s,x,xx} 为坐标和为 ss,第一个人在 (x,sx)(x,s-x),第二个人在 (xx,sxx)(xx,s-xx)

接下来思考状态转移方程,其实就是由朴素版推出来的:

dps,x,xx=max{dps1,x1,xx,dps1,x,xx1,dps1,x1,xx1,dps1,x,xx}dp_{s,x,xx}=\max\{dp_{s-1,x-1,xx},dp_{s-1,x,xx-1},dp_{s-1,x-1,xx-1},dp_{s-1,x,xx}\}

复杂度就变成 Θ(n3)\Theta(n^3)


初始值

在开始的时候,我们要将所有状态设为不可达。但是 dp2,1,1dp_{2,1,1} 的状态是确定的。dp2,1,1a1,1dp_{2,1,1}\gets a_{1,1}

Code\large\color{skyblue} Code

#include<bits/stdc++.h>
using namespace std;
const int N = 3e2+1;
int a[N][N],dp[N<<1][N][N],n;
int main() {
	memset(dp,-0x3f,sizeof dp);
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++) {
		for(int j=1;j<=n;j++) {
			cin>>a[i][j];
		}
	}
	dp[2][1][1]=a[1][1];
	for(int i=3;i<=n<<1;i++) {
		for(int j=1;j<=n;j++) {if(i-j<1||i-j>n) continue;//枚举 x;y为 i-x+1,不能越界
			for(int k=1;k<=n;k++) {if(i-k<1||i-k>n) continue;//同上 
				int t=0;
				if(j==k) t=a[j][i-j];//相同只算一个 
				else t=a[j][i-j]+a[k][i-k];
				dp[i][j][k]=max(max(dp[i-1][j-1][k],dp[i-1][j][k-1]),max(dp[i-1][j][k],dp[i-1][j-1][k-1]))+t;
			}
		}
	}
	cout<<dp[n<<1][n][n];
	return 0;
}

T5-Bottles

T5-Bottles

题意

nn 瓶水,第 ii 瓶水的水量为 aia_i,容量为 bib_i。将 11 单位水从一个瓶子转移到另一个瓶子所消耗时间为 11 秒,且可以进行无限次转移。求储存所有水所需最小瓶子数 kk 以及该情况下所用最小时间 tt


General Idea\Large\color{skyblue} General \ Idea

一步一步的做题,找思路。

第一问

对于第一问,非常容易。设 sum=i=1naisum=\sum\limits^n_{i=1}a_i。只需要排序,然后找到最大的满足 j=1iajsum\sum\limits_{j=1}^ia_j\ge sumii,就是第一问的答案,记为 limitslimits

第二问

对于最优解问题,考虑 dp。

定义状态

有以下条件需要被满足:

  • nn 个水瓶进行考虑选择与否。

  • 选择的水瓶数量不能超过 limitslimits

  • 要有足够的容量装水。

其实也可以看做背包问题,价格为 bib_i,价值为 aia_i


我们就可以以此定义 dpi,j,kdp_{i,j,k} 为考虑了第 ii 个水瓶,选择了 jj 个,容量共有 kk 的最大 aia_i 之和。

为什么是最大值?因为 sumsum 一定。如果不用转移的水更多,要转移的水更少。

状态转移方程

根据背包问题的解法,对第 ii 个瓶子分类讨论。有选与不选,即:

dpi,j,k=max{dpi1,j,k,dpi1,j1,kbi+ai}dp_{i,j,k}=\max\{dp_{i-1,j,k},dp_{i-1,j-1,k-b_i}+a_i\}
#include<bits/stdc++.h>
#define b(__) b[mp[__]]
using namespace std;
const int N=1e2+1;
int n,a[N],ans=1e9,b[N],mp[N],sum,limits=1,S;
int dp[N][N*N];//第 i 个盘子,选 j 个 容量为 k 
int main() {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++) cin>>a[i],sum+=a[i],mp[i]=i;
	for(int i=1;i<=n;i++) cin>>b[i],S+=b[i];
	sort(mp+1,mp+n+1,[](int x,int y) {return b[x]>b[y];});
	for(int i=1,t=0;i<=n;i++) {
		t+=b(i);
		if(t>=sum) {
			limits=i;
			break;
		}
	}
	memset(dp,-0x3f,sizeof dp);
    dp[0][0]=0;//赋初始值 
	for(int i=1;i<=n;i++)
		for(int j=min(limits,i);j>=1;j--)
			for(int k=S;k>=b[i];k--)//此处 a,b 排序与否均可
				dp[j][k]=max(dp[j][k],dp[j-1][k-b[i]]+a[i]);
	for(int i=sum;i<=S;i++) ans=min(sum-dp[limits][i],ans);
	//此时要有合法的状态!若 i<sum,说明装不下 
	cout<<limits<<" "<<ans<<"\n";
	return 0;
}

T6-Cipher

不写了,看 hht 的题解


总结,简单题挂小分,难题根本不会,dp 仍需努力。dfs 水平有所提升

posted @ 2023-08-16 20:45  cjrqwq  阅读(28)  评论(0)    收藏  举报  来源