codeforces 两道(dp、思维)(C.Ivan the Fool and the Probability Theory)( E. By Elevator or Stairs?)

传送:https://codeforces.com/contest/1248/problem/C

题目:n x m的网格 (10^5),给网格涂上白黑两色,要求一种颜色网格最多有一个相同颜色的网格和它相邻,问总共有多少种涂色方案?答案对10^9取模。

思路:说实话,当时没想出来,但知道应该是dp。

我们可以从第一行开始考虑。

1. 如果第一行有 两个相同颜色格子相邻 的情况,那么与这行相邻的下一行也就随之确定,以此类推,整个网格的涂色就确定了。

此种情况,方案数为 第一行涂色方案数 - 第一行相邻格子交替涂色方案数 (黑白相间+白黑相间=2)。

2. 如果第一行不存在 两个相同颜色格子相邻 的情况,即该行网格总是 白黑相间,那么与这行相邻的下一行也就不存在 两个相同颜色格子相邻 的情况,以此类推。此种情况,方案数为 第一列涂色方案数。只要第一列确定,每一行的第一格也就确定,每一行白黑相间 也就一种情况。

我们用一个二维数组dp[maxn][2]来为维护一行网格的涂色方案数。

dp[i][0] 表示第i个位置涂白色 的方案数

dp[i][0] = dp[i-1][1] + dp[i-2][1] 

第i个位置为白色,那么可以由两种情况转移而来

  1. 前面两个位置可以为 黑、白 -> dp[i-2][1]
  2. 前面两个位置可以为 黑、黑 -> dp[i-2][0]

dp[i][1] 表示第i个位置涂黑色 的方案数 

dp[i][1] = dp[i-1][0] + dp[i-2][0]

第i个位置为黑色,那么可以由两种情况转移而来

  1. 前面两个位置可以为 白、黑 -> dp[i-2][0]
  2. 前面两个位置可以为 白、白 -> dp[i-2][1]

二者综合,dp[i][0] + dp[i][1] = dp[i-1][1] + dp[i-1][0] + dp[i-2][1] + dp[i-2][0]   ->   dp[i] = dp[i-1] + dp[i-2]

总方案数,即 dp[m] - 2 + dp[n]

代码:

#include
#define LL long long
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn=100005;
const int mod=1e9+7;
int n,m;
LL dp[maxn];
int main()
{
	cin>>n>>m;
	ios::sync_with_stdio(false);
	dp[1]=2;	
	dp[2]=4;
	for(int i=3;i<=max(n,m);i++)
	{
		dp[i]=dp[i-1]+dp[i-2];
		dp[i]%=mod;
	}
	LL ans=(dp[n]+dp[m]-2+mod)%mod;
	cout << ans << endl;
	return 0;	
}

传送:https://codeforces.com/contest/1249/problem/E

题目:有一栋n层的楼房,有两种方式上楼,乘坐电梯和爬楼梯,爬楼梯给出了从下面一层到这层需要花费的时间a[1]...a[n-1]

乘坐电梯也给出了从下面一层到这层需要花费的时间b[1]...b[n-1],但乘上电梯前需要等待c时间,问从第一层到达各层楼需要花费的最小时间分别是多少?

思路:很明显也是dp递推,一开始我用了贪心的思路,以为第i层的最优解,只是从前一层的最优直接转移而来,这是个错误的做法,因为该层的最优解还可能是之前的次优解转移而来。(通过错误代码体会)

而正确的做法应该用一个二维数组dp[maxn][2],去维护结果

dp[i][0] 表示上一步是通过爬楼梯到达此层的最小时间

dp[i][1] 表示上一步是通过坐电梯到达此层的最小时间

dp[i][0]=min(dp[i-1][0]+a[i-1],dp[i-1][1]+a[i-1])

dp[i][1]=min(dp[i-1][0]+b[i-1]+c,dp[i-1][1]+b[i-1])

错误代码:

#include
#define LL long long
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn=200005;
const int mod=1e9+7;
LL a[maxn],b[maxn],dp[maxn];
int main()
{
	ios::sync_with_stdio(false);
	int n,c;
	cin>>n>>c;
	for(int i=1;i>a[i];
	}	
	for(int i=1;i>b[i];
	}
	dp[1]=0;
	int flag=1;//代表是否可以无需等待乘坐电梯 
	for(int i=2;i<=n;i++)
	{
		dp[i]=dp[i-1];
		if(a[i-1]

正确代码:

#include
#define LL long long
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn=200005;
const int mod=1e9+7;
LL a[maxn],b[maxn];
LL dp[maxn][2];
int main()
{
	ios::sync_with_stdio(false);
	int n,c;
	cin>>n>>c;
	for(int i=1;i>a[i];
	}	
	for(int i=1;i>b[i];
	}
	dp[1][0]=0;
	dp[1][1]=INF;
	cout << 0 << ' ';
	for(int i=2;i<=n;i++)
	{
		dp[i][0]=min(dp[i-1][0]+a[i-1],dp[i-1][1]+a[i-1]);
		dp[i][1]=min(dp[i-1][0]+b[i-1]+c,dp[i-1][1]+b[i-1]);
		
		cout << min(dp[i][0],dp[i][1]) << ' ';
	}
	cout << endl;
	return 0;
}

你可能感兴趣的:(dp,acm)