CF14E Camels(暴力dp || 优化dp)

本文介绍了两篇关于洛谷题目解决方案的博客,主要涉及动态规划思路。第一篇博客通过暴力递推的方法,用O(nt^2)的时间复杂度解决了一道关于排列满足特定条件的计数问题。第二篇博客则从图形角度出发,通过确保序列形成t个山峰和t-1个山谷来简化问题,最终得出答案。两篇文章都展示了如何巧妙地运用动态规划技巧来解决问题。
摘要由CSDN通过智能技术生成

 洛谷链接:

Camels - 洛谷

思路:

1.考虑暴力AC。

设f[i][j][k][a1][a2]为第i位,a[i]=j,a[i−1]=k,已经满足a1个要求1,a2个要求2的方案数

然后暴力转移就好了,复杂度O(nt^2)

注意dp逻辑,c是已经求出的dp值的位置,用c的情况来推出c+1,所以c只用遍历到n-1。

#include <bits/stdc++.h>
using namespace std;
#define int long long
/*
考虑暴力AC。
设f[i][j][k][a1][a2]为第i位,a[i]=j,a[i−1]=k,已经满足a1个要求1,a2个要求2。
然后暴力转移就好了,复杂度O(nt^2)
*/
int n, t, f[21][5][5][11][11];
signed main(){
	cin >> n >> t;
	for(int i=1; i<=4; i++)
	for(int j=1; j<=4; j++)
		if(i!=j) f[2][i][j][0][0]=1;
	for(int c=2; c<=n-1; c++) //cur pos
	for(int i=1; i<=4; i++) //left
	for(int j=1; j<=4; j++) //mid
	for(int k=1; k<=4; k++) //right
	for(int a1=0; a1<=t; a1++)
	for(int a2=0; a2<=t-1; a2++){
		if(i==j || j==k) continue; //相邻相等,跳过
		if(i<j && j>k) f[c+1][j][k][a1+1][a2] += f[c][i][j][a1][a2];
		else if(i>j && j<k) f[c+1][j][k][a1][a2+1] += f[c][i][j][a1][a2];
		else f[c+1][j][k][a1][a2] += f[c][i][j][a1][a2];
	}

	int ans = 0;
	for(int i=1; i<=4; i++)
	for(int j=1; j<=4; j++){
		if(i==j) continue;
		ans += f[n][i][j][t][t-1];
	}
	cout << ans;
}

2.根据题意,如果根据数字画一个折线图,有t个山峰,t-1个山谷,所以可以让一开始必定上升,然后只考虑t个山峰,最后只要趋势是下降的,就必然是t-1个山谷。

#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, t, f[21][11][5][2];
//当前位置,当前满足几个条件1,当前数值,目前是上升/下降(0/1)

signed main(){
	cin >> n >> t; //位置数,条件个数
	//初始化2位置的上升、下降情况
    f[2][0][4][0]=3;
    f[2][0][3][0]=2;
    f[2][0][2][0]=1;

	for(int c=3; c<=n; c++) //当前位置
	for(int m=0; m<=t; m++) //满足几个条件1
	for(int i=1; i<=4; i++) //上一个数
	for(int j=1; j<=4; j++) //当前数
	{
		if(i<j) //当前数大,上升
			f[c][m][j][0] += f[c-1][m][i][0] + f[c-1][m][i][1];
		if(i>j) //当期数小,下降,同时需要统计峰的数量(上次升,这次降)
			f[c][m][j][1] += f[c-1][m][i][1] + (m>0 ? f[c-1][m-1][i][0] : 0);
	}
	int ans = 0;
	for(int i=1; i<=4; i++)
		ans += f[n][t][i][1];
	cout << ans;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值