洛谷链接:
思路:
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;
}