【BZOJ4321】queue2

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4321


根据zhhx大神的说法,这是一道套路题。。。

设dp[i][j][0]表示插完i,有j对相邻且差为1的数对,i与i-1不相邻;dp[i][j][1]表示插完i,有j对相邻且差为1的数对,i与i-1相邻。

然后我们分类讨论,先考虑推dp[i][j][1],因为他要求i与i-1相邻,所以情况更少些。

若i-1与i-2相邻,则i有两种方法,放在i-1与i-2之间,数对数量并不会改变,放在i-1另一边会产生一对数对,因此方案数+=dp[i-1][j][1]+dp[i-1][j-1][1];

若i-1与i-2不相邻,则i需要放到i-1两边,且会产生一对数对,方案数+=dp[i-1][j-1][0]*2。

然后考虑dp[i][j][0],相对会麻烦一些。

若i-1与i-2相邻,且放上i后会破坏一对数对,则共有j+1对数对之间放完会破坏一对,而i-1与i-2那一对之间不可以放,因此有j个位置。

若i-1与i-2不相邻,且放上i后会破坏一对数对,此时就有j+1个位置了。

若i-1与i-2相邻,且放上i不会破坏数对,原先有i个位置(此时放好i-1个元素),除去j个会破坏数对的位置和i-1与i-2的另一边(与i-2相隔i-1),共有i-j-1个位置。

若i-1与i-2不相邻,且放上i不会破坏数对,原先有i个位置,j个位置会破坏数对,i-1两边都不可以去,所有有i-j-2个位置。

综上,dp[i][j][0]=dp[i-1][j+1][1]*j+dp[i-1][j+1]*(j+1)+dp[i-1][j][1]*(i-j-1)+dp[i-1][j][0]*(i-j-2)。

然后考虑边界,显然dp[1][0][0]=1,而且当i=1时,也就这么一个合法状态。

 1 #include <cstdio>
 2 
 3 typedef long long ll;
 4 
 5 const int maxn = 1005, mod = 7777777;
 6 
 7 ll dp[maxn][maxn][2];
 8 
 9 int main() {
10     int n;
11     scanf("%d", &n);
12     dp[1][0][0] = 1;
13     for (int i = 2; i <= n; ++i)
14         for (int j = 0; j <= n; ++j) {
15             dp[i][j][0] = (dp[i - 1][j + 1][1] * j + dp[i - 1][j + 1][0] * (j + 1)) % mod;
16             dp[i][j][0] = (dp[i][j][0] + dp[i - 1][j][0] * (i - j - 2) + dp[i - 1][j][1] * (i - j - 1)) % mod;
17             dp[i][j][1] = dp[i - 1][j][1];
18             if (j >= 1) dp[i][j][1] = (dp[i][j][1] + dp[i - 1][j - 1][1] + dp[i - 1][j - 1][0] * 2) % mod;
19         }
20     printf("%lld", dp[n][0][0]);
21     return 0;
22 }
AC代码
原文地址:https://www.cnblogs.com/Mr94Kevin/p/9897236.html