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

    题目描述

    n 个沙茶,被编号 1~n。排完队之后,每个沙茶希望,自己的相邻的两人只要无一个人的编号和自己的编号相差为 1(+1 或-1)就行; 
    现在想知道,存在多少方案满足沙茶们如此不苛刻的条件。 

    输入

    只有一行且为用空格隔开的一个正整数 N,其中 100%的数据满足 1≤N ≤ 1000; 

    输出

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

    样例输入

    4

    样例输出


    题解

    dp

    老套路了,考虑把数从小到大插入的过程进行dp。

    设 $f[i][j]$ 表示 $1sim i$ 的排列,有 $j$ 组相邻的相差1,且 $i$ 和 $i-1$ 不相邻的方案数;
    设 $g[i][j]$ 表示 $1sim i$ 的排列,有 $j$ 组相邻的相差1,且 $i$ 和 $i-1$ 相邻的方案数。

    那么考虑插入 $i+1$ 的位置,有:不破坏空位且不与 $i$ 相邻、不破坏空位且与 $i$ 相邻、破坏空位且不与 $i$ 相邻、破坏空位且与 $i$ 相邻(只发生在 $g$ 的转移)4种。分别推一下方案数即可。

    最后的答案就是 $f[n][0]$ 。

    时间复杂度 $O(n^2)$ 。

    另外把前几项丢到oeis上可以得到线性递推式 $a_n=(n+1)a_{n-1}-(n-2)a_{n-2}-(n-5)a_{n-3}+(n-3)a_{n-4}$ ,就能 $O(n)$ 求解了,感觉像是某容斥然而并不能推出来...

    #include <cstdio>
    #define mod 7777777
    long long f[1010][1010] , g[1010][1010];
    int main()
    {
    	int n , i , j;
    	scanf("%d" , &n);
    	f[1][0] = 1;
    	for(i = 1 ; i < n ; i ++ )
    	{
    		for(j = 0 ; j < i ; j ++ )
    		{
    			f[i + 1][j] = (f[i + 1][j] + f[i][j] * (i - j - 1)) % mod;
    			g[i + 1][j + 1] = (g[i + 1][j + 1] + f[i][j] * 2) % mod;
    			if(j) f[i + 1][j - 1] = (f[i + 1][j - 1] + f[i][j] * j) % mod;
    			f[i + 1][j] = (f[i + 1][j] + g[i][j] * (i - j)) % mod;
    			g[i + 1][j + 1] = (g[i + 1][j + 1] + g[i][j]) % mod;
    			if(j) f[i + 1][j - 1] = (f[i + 1][j - 1] + g[i][j] * (j - 1)) % mod;
    			g[i + 1][j] = (g[i + 1][j] + g[i][j]) % mod;
    		}
    	}
    	printf("%lld
    " , f[n][0]);
    	return 0;
    }
    
    

     

  • 相关阅读:
    [Python] 糗事百科文本数据的抓取
    [Python] 文件扫描
    [Python] 根据博客园用户名抓取其所有文章的标题及其链接
    ParagraphString
    IrregularGridCollectionView处理不定宽度的标签cell
    Java多线程与并发
    设计模式之代理模式
    javascript设置百分比保留两位小数。
    Java基础知识总结(异常机制、集合、JUC、IO)
    Java底层知识JVM、GC
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8564471.html
Copyright © 2011-2022 走看看