• BZOJ1801或洛谷2051 [AHOI2009]中国象棋


    BZOJ原题链接

    洛谷原题链接

    这题挺难想状态的,刚看题感觉是状压,但数据(100)显然不可能。
    注意到每行每列只能放(0sim 2)个棋子,所以我们可以将这个写入状态。
    (f[i][j][k])表示放了前(i)行,共有(j)列只放了一个棋子,共有(k)列放了两个棋子,而没有放棋子的列数则可以直接计算,即(m - j - k)
    然后分类讨论。


    • (i)行不放
      只有一种放法,直接由上一层转移:$$f[i][j][k] = f[i][j][k] + f[i - 1][j][k]$$

    • (i)行放一个棋子
    1. 放在原本没有放棋子的列上,共(m - (j - 1) - k)种放法:$$f[i][j][k] = f[i][j][k] + f[i - 1][j - 1][k] imes (m - (j - 1) - k)$$
    2. 放在原本只有一个棋子的列上,共(j + 1)种放法:$$f[i][j][k] = f[i][j][k] + f[i - 1][j + 1][k - 1] imes (j + 1)$$

    • (i)行放两个棋子
    1. 都放在原本没有放棋子的列上,共(C_{m - (j - 2) - k} ^ 2)种放法:$$f[i][j][k] = f[i][j][k] + f[i - 1][j - 2][k] imes C_{m - (j - 2) - k} ^ 2$$
    2. 一个放在空列,一个放在原本只有一个棋子的列上,共(j imes (m - j - (k - 1)))种放法:$$f[i][j][k] = f[i][j][k] + f[i - 1][j][k - 1] imes j imes (m - j - (k - 1))$$
    3. 都放在原本只有一个棋子的格子上,共(C_{j + 2} ^ 2)种放法:$$f[i][j][k] = f[i][j][k] + f[i - 1][j + 2][k - 2] imes C_{j + 2} ^ 2$$

    初值(f[0][0][0] = 1),其它为(0)
    (DP)过程中注意取模和边界问题。
    最后答案就是(sumlimits_{i = 0} ^ m sum limits _{j = 0} ^ m f[n][i][j])

    #include<cstdio>
    using namespace std;
    const int N = 110;
    const int mod = 9999973;
    int f[N][N][N];
    inline int re()
    {
    	int x = 0;
    	char c = getchar();
    	bool p = 0;
    	for (; c < '0' || c > '9'; c = getchar())
    		p |= c == '-';
    	for (; c >= '0' && c <= '9'; c = getchar())
    		x = x * 10 + c - '0';
    	return p ? -x : x;
    }
    inline int C(int x)
    {
    	return (1LL * x * (x - 1) >> 1) % mod;
    }
    int main()
    {
    	int i, j, k, n, m, s = 0;
    	n = re();
    	m = re();
    	f[0][0][0] = 1;
    	for (i = 1; i <= n; i++)
    		for (j = 0; j <= m; j++)
    			for (k = 0; k + j <= m; k++)
    			{
    				f[i][j][k] = f[i - 1][j][k];
    				if (k)
    				{
    					f[i][j][k] = ((1LL * f[i - 1][j + 1][k - 1] * (j + 1) % mod) + f[i][j][k]) % mod;
    					f[i][j][k] = ((1LL * f[i - 1][j][k - 1] * j % mod * (m - j - k + 1) % mod) + f[i][j][k]) % mod;
    				}
    				if (j)
    					f[i][j][k] = ((1LL * f[i - 1][j - 1][k] * (m - j - k + 1) % mod) + f[i][j][k]) % mod;
    				if (j > 1)
    					f[i][j][k] = ((1LL * f[i - 1][j - 2][k] * C(m - j - k + 2) % mod) + f[i][j][k]) % mod;
    				if (k > 1)
    					f[i][j][k] = ((1LL * f[i - 1][j + 2][k - 2] * C(j + 2) % mod) + f[i][j][k]) % mod;
    			}
    	for (i = 0; i <= m; i++)
    		for (j = 0; j <= m; j++)
    			s = (1LL * s + f[n][i][j]) % mod;
    	printf("%d", s);
    	return 0;
    }
    
  • 相关阅读:
    [CSP-S模拟测试]:军训队列(DP+乱搞)
    [CSP-S模拟测试]:stone(结论+桶+前缀和+差分)
    [CSP-S模拟测试]:bird(线段树优化DP)
    [CSP-S模拟测试]:maze(二分答案+最短路)
    [CSP-S模拟测试]:优化(贪心+DP)
    uoj132/BZOJ4200/洛谷P2304 [Noi2015]小园丁与老司机 【dp + 带上下界网络流】
    Miiler-Robin素数测试与Pollard-Rho大数分解法
    hdu4336 Card Collector 【最值反演】
    loj2542 「PKUWC2018」随机游走 【树形dp + 状压dp + 数学】
    loj2540 「PKUWC2018」随机算法 【状压dp】
  • 原文地址:https://www.cnblogs.com/Iowa-Battleship/p/9842424.html
Copyright © 2020-2023  润新知