https://atcoder.jp/contests/arc146/tasks/arc146_e
Trick1 超长序列从值域入手(判定转状态)
通过绝对值的条件,其实我们可以从小到大放每个数。
对于两个相邻的同样数 i i i,他们之间必须放 i + 1 i+1 i+1
因此可以设计 d p [ i ] [ j ] [ 0 / 1 / 2 ] dp[i][j][0/1/2] dp[i][j][0/1/2] 表示前 i i i 个数,第 i i i 个有 j j j 个相邻的,左右两边有多少个为 i i i
Trick2 分析dp状态数量
此时状态是 O ( n 2 ) O(n^2) O(n2) 的。
但观察dp的转移过程很单一,相邻之间的转移相差也就1,而且第三维是类似一种层数的东西,只能从高层到低层。
此时大胆猜测状态数并不多。手玩一下可以发现,在第一、三维确定时,第二维的取值只有3种,然后记搜就完事了
int dfs(int i, int o, int k) {
if(k<0 || k>=a[i]) return 0;
if(i<=1) return dp[i][o][k];
if(dp[i][o].find(k)!=dp[i][o].end()) return dp[i][o][k];
int tmp=0;
if(o==0) tmp=(dfs(i-1, 0, a[i]-k)+dfs(i-1, 1, a[i]-k)+dfs(i-1, 2, a[i]-k))%mo;
if(o==1) tmp=(dfs(i-1, 1, a[i]-k-1)+dfs(i-1, 2, a[i]-k-1)*2)%mo;
if(o==2) tmp=dfs(i-1, 2, a[i]-k-2);
return dp[i][o][k]=tmp*C(a[i]-1, a[i]-k-1)%mo;
}