zoukankan      html  css  js  c++  java
  • codeforces 1051 D. Bicolorings (DP)

    D. Bicolorings
    time limit per test
    2 seconds
    memory limit per test
    256 megabytes
    input
    standard input
    output
    standard output

    You are given a grid, consisting of $$$2$$$ rows and $$$n$$$ columns. Each cell of this grid should be colored either black or white.

    Two cells are considered neighbours if they have a common border and share the same color. Two cells $$$A$$$ and $$$B$$$ belong to the same component if they are neighbours, or if there is a neighbour of $$$A$$$ that belongs to the same component with $$$B$$$.

    Let's call some bicoloring beautiful if it has exactly $$$k$$$ components.

    Count the number of beautiful bicolorings. The number can be big enough, so print the answer modulo $$$998244353$$$.

    Input

    The only line contains two integers $$$n$$$ and $$$k$$$ ($$$1 le n le 1000$$$, $$$1 le k le 2n$$$) — the number of columns in a grid and the number of components required.

    Output

    Print a single integer — the number of beautiful bicolorings modulo $$$998244353$$$.

    Examples
    Input
    3 4
    Output
    12
    Input
    4 1
    Output
    2
    Input
    1 2
    Output
    2
    Note

    One of possible bicolorings in sample $$$1$$$:

    题意
    给一个2行n列的矩阵填上黑色和白色,求连通块个数为k个的填色方案数量(mod 998244353)
    分析
    因为只有两行,为n-1列的矩阵增加1列的情况数只有很少,容易想到用 $$$(i, k)$$$ 表示 $$$i$$$ 列有 $$$k$$$ 个连通块的矩阵, 但是它在向 $$$i+1$$$ 列的矩阵转移时,需要知道最后一列的状态,所以可以用 $$$0$$$, $$$1$$$, $$$2$$$, $$$3$$$表示最后一列为 $$$00$$$, $$$01$$$, $$$10$$$, $$$11$$$,那么状态就增加一维变成 $$$(i, k, s)$$$,然后就是分析递推关系:

    $$$(i,k,0)$$$ 的矩阵,可以由 $$$i-1$$$ 列的矩阵添加一列 $$$00$$$ 得到,当它的结尾为 $$$00$$$, $$$01$$$, $$$10$$$, $$$11$$$时,分别会让连通块个数:不变,不变,不变,+1,所以 $$$(i,k,0)$$$由 $$$(i-1,k,0)$$$, $$$(i-1,k,1)$$$, $$$(i-1,k,2)$$$, $$$(i-1,k-1,3)$$$得到: $$$$$$ egin{align} dp[i][k][0,0]=~~~& dp[i-1][k][0,0]\ +& dp[i-1][k][0,1]\ +& dp[i-1][k][1,0]\ +& dp[i-1][k-1][1,1] end{align} $$$$$$ $$$(i,k,1)$$$的矩阵同理,为$$$i-1$$$列的矩阵添加 $$$01$$$,当结尾为 $$$00$$$, $$$01$$$, $$$10$$$, $$$11$$$时,分别会使连通块的个数:+1,不变,+2,+1,所以$$$(i,k,1)$$$由$$$(i-1,k-1,0)$$$,$$$(i-1,k,1)$$$,$$$(i-1,k-2,2)$$$,$$$(i-1,k-1,3)$$$得到: $$$$$$ egin{align} dp[i][k][0,1]=~~~& dp[i-1][k-1][0,0]\ +& dp[i-1][k][0,1]\ +& dp[i-1][k-2][1,0]\ +& dp[i-1][k-1][1,1] end{align} $$$$$$ (i,k,2)同理可得: $$$$$$ egin{align} dp[i][k][1,0]=~~~& dp[i-1][k-1][0,0]\ +& dp[i-1][k-2][0,1]\ +& dp[i-1][k][1,0]\ +& dp[i-1][k-1][1,1] end{align} $$$$$$ (i,k,3)同理可得: $$$$$$ egin{align} dp[i][k][1,1]=~~~& dp[i-1][k-1][0,0]\ +& dp[i-1][k][0,1]\ +& dp[i-1][k][1,0]\ +& dp[i-1][k][1,1] end{align} $$$$$$ 于是得到了完整的递推公式,只需要从下面的状态开始, $$$$$$ egin{align} dp[1][1][0,0]=1\ dp[1][2][0,1]=1\ dp[1][2][1,0]=1\ dp[1][1][1,1]=1 end{align} $$$$$$ 就能推到出所有的状态,最后对dp[n][k]的所有情况求和就是答案了。

    注意当k为1时,是不存在k-2的状态的,需要特判一下避免超出数组范围
    总结
    动态规划的状态定义很关键,必须抓住状态之间的联系;递推式的推导也需要深入思考
    代码
    #include<stdio.h>
    typedef long long LL;
    #define mod 998244353
    int dp[1003][2006][4] = {0};
    int main() {
        int n, lm;
        scanf("%d %d", &n, &lm);
        //初始化
        dp[1][1][0] = 1;//00
        dp[1][2][2] = 1;//10
        dp[1][2][1] = 1;//01
        dp[1][1][3] = 1;//11
        LL temp=0;
        for (int i = 2; i <= n; ++i) {
            for (int k = 1; k <= (i << 1); ++k) {
                temp = 0;//使用temp求和来避免溢出
                temp =temp
                    + dp[i - 1][k][1]//01
                    + dp[i - 1][k][0]//00
                    + dp[i - 1][k][2]//10
                    + dp[i - 1][k - 1][3];//11
                dp[i][k][0] = temp % mod;
                temp = 0;
                temp = temp 
                    + dp[i - 1][k][1]//01
                    + dp[i - 1][k-1][0]//00
                    + (k>=2?dp[i - 1][k - 2][2]:0)//10
                    + dp[i - 1][k-1][3];//11
                dp[i][k][1] = temp%mod;
                temp = 0;
                temp = temp 
                    + (k>=2?dp[i - 1][k - 2][1]:0)//01
                    + dp[i - 1][k-1][0]//00
                    + dp[i - 1][k][2]//10
                    + dp[i - 1][k-1][3];//11
                dp[i][k][2] = temp%mod;
                temp = 0;
                temp = temp 
                    + dp[i - 1][k][1]//01
                    + dp[i - 1][k - 1][0]//00
                    + dp[i - 1][k][2]//10
                    + dp[i - 1][k][3];//11
                dp[i][k][3] = temp%mod;
                temp = 0;
            }
        }
        LL ans = 0;
        ans = ans + dp[n][lm][0] + dp[n][lm][1] + dp[n][lm][2] + dp[n][lm][3];
        ans = ans%mod;
        printf("%I64d
    ", ans);
    }
  • 相关阅读:
    Objective-C多线程-02
    Objective-C多线程-01
    Objective-C的属性与实例变量
    KVO的内部实现原理
    ASIHTTPRequest 和 AFNetWorking 的比较
    Python类和函数_规划式开发
    禁用密码登录,改用key秘钥对登录
    Python类和函数_时间与纯函数
    Python类和对象_调试与术语
    Python类和对象_修改和复制
  • 原文地址:https://www.cnblogs.com/tobyw/p/9685639.html
Copyright © 2011-2022 走看看