zoukankan      html  css  js  c++  java
  • 【BZOJ4321】queue2【dp】

    【BZOJ4321】queue2【dp】

    题目描述

    (n) 个沙茶,被编号 (1~n)。排完队之后,每个沙茶希望,自己的相邻的两人只要无一个人的编号和自己的编号相差为 (1)(+1)(-1))就行;

    现在想知道,存在多少方案满足沙茶们如此不苛刻的条件。

    输入格式

    只有一行且为用空格隔开的一个正整数 (N)

    输出格式

    一个非负整数,表示方案数对 7777777 取模。

    样例

    样例输入

    4
    

    样例输出

    2
    

    样例解释

    有两种方案 (2 4 1 3)(3 1 4 2)

    数据范围与提示

    对于(30\%)的数据满足(Nleqslant 20)

    对于(100\%)的数据满足 ;(1leqslant N leqslant 10^4)

    分析

    这种带有这种限制的 (dp) 题,我们通常的状态定义就是前 (i)(j) 结尾的方案数是多少,但是这个题并不能这样写,因为下一个放置的人的编号会影响当前放置编号后的状态,所以我们换一个思路:

    定义 (f[i][j][0/1]) 表示向序列中插入元素 (i) ,当前有 (j) 对两两之间相差一的人, (0/1)表示当前插入的 (i) 是否和 (i-1)挨着,那么由于第三维的不确定性,我们需要考虑两个状态转移。

    首先看 (f[i][j][1]) 的转移,因为 (f[i][j][1]) 表示当前插入 (i) 后有 (j) 对编号相差一的,因为这里表示插入后 (i)(i-1) 是相邻的,所以只可能从 (j-1) 对或者 (j) 对转移来。当 (i-1)(i-2) 相邻的时候,也就是第三维是 (1) ,这时候会有两种能转移来的方案:

    一个是从 (f[i-1][j][1]) 转移来,这时候我们只需要把 (i)插入到 (i-1)(i-2) 中间就行。

    还有一个是从 (f[i-1][j-1][1]) 转移来,我们只需要在 (i-1) 不和 (i-2) 挨着的那一侧插入 (i) 即可。

    然后考虑第三维是 (0) ,这时候只可能从 (f[i-1][j-1][0]) 转移来,因为要求 (i)(i-1) 必须相邻,这时候 (i-1)(i-2) 是不相邻的,所以我们有两种插入方法,在 (i-1) 左侧和右侧。那么这个转移方程就是:

    [f[i][j][1] = f[i-1][j][1] + 2 imes f[i-1][j-1][0] + f[i-1][j-1][1] ]

    然后就是 (f[i][j][0]) 的转移,当前如果 (i)(i-1) 不相邻,那么只可能让 (j) 不变或者减小,所以上一个的 (j) 只可能是 (j)(j+1)

    首先考虑从 (f[i-1][j+1][0]) 的转移 这时候只需要在 (j+1) 段中任意插入个 (i) 就成了 (f[i][j][0]) ,而这时候有 (j+1) 种,也就是 (f[i-1][j+1][0] imes (j+1))

    然后是 (f[i-1][j+1][1]) 这时候不能插入到 (i-1)(i-2) 的这一段中,所以情况有 (j) 种,也就是 (f[i-1][j+1][1] imes j)

    然后分析上一次也有 (j) 对的情况,如果挨着,即(f[i-1][j][1]),那么可以在除了这些对之外的位置放,一共有 (i-j-2) 种,因为也可以在 (i-1)(i-2) 之间放,所以有 (i-j-1) 种,不挨着的情况与这个类似,只不过只能在这些对之外的地方放,那么状态转移方程就是:

    [f[i][j][0] = f[i-1][j+1][0] imes (j+1) + f[i-1][j+1][1] imes j + f[i-1][j][1] imes (i-j-1) + f[i-1][j][0] imes (i-j-2) ]

    代码

    #include<cstdio>
    using namespace std;
    #define ll long long
    const int maxn = 1000+10;
    const int mod = 7777777;
    ll f[maxn][maxn][2];
    int main(){
    	int n;
    	scanf("%d",&n);
    	f[2][1][1] = 2;
    	for(int i=3;i<=n;++i){
    		for(int j=0;j<i;++j){
    			f[i][j][0] = (f[i-1][j+1][0] * (j+1) + f[i-1][j+1][1] * j + f[i-1][j][1] * (i-j-1) + f[i-1][j][0] * (i-j-2))%mod;
    			if(j)f[i][j][1] = (f[i-1][j][1] + 2 * f[i-1][j-1][0] + f[i-1][j-1][1])%mod;
    		}
    	}
    	printf("%lld
    ",f[n][0][0]);
    	return 0;
    }
    
  • 相关阅读:
    hdu 5101 Select
    hdu 5100 Chessboard
    cf B. I.O.U.
    cf C. Inna and Dima
    cf B. Inna and Nine
    cf C. Counting Kangaroos is Fun
    Radar Installation 贪心
    spfa模板
    Sequence
    棋盘问题
  • 原文地址:https://www.cnblogs.com/Vocanda/p/13488490.html
Copyright © 2011-2022 走看看