CF 1027E Inverse Coloring

当天晚上并没有看懂题意,然后就刚了40分钟F,但是没有弄出来呜呜呜。

推荐博客:  https://blog.csdn.net/Dream_maker_yk/article/details/81840495

考虑到我们写出一行和一列的情况就可以还原出整个正方形,而这一行和这一列的长度是一样的,所以我们可以合在一起dp。

我们设$f_{i, j}$表示在前$i$个格子中最长的一个颜色的长度为$j$的方案数,有转移方程:

    $f_{i, j} = \sum_{j = 1}^{i}\sum_{k = 1}^{j}f_{i - k, min(j, i - k)}$

注意到这时候我们算出来的$f_{i, j}$实际上是包含了$f_{i, j - 1}, f_{i, j - 2}...$的情况的,所以我们再差分一遍使$f_{i, j}$的定义表示为长度为$i$的序列中最长的连续相同的颜色段恰好为$j$的方案数。

然后我们只要枚举这个连续的最长段的长度去累加答案就好了,其实到现在为止我们都只是计算了一种颜色的情况,考虑到把黑白格子反一反就可以得到完全相同的另外的合法情况,所以最后把答案乘以二。

枚举时注意小细节$j$的范围要小于$n$,我就是这样RE了一次。

Code:

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;

const int N = 505;
const ll P = 998244353LL;

int n, siz;
ll f[N][N];

inline int min(int x, int y) {
    return x > y ? y : x;
}

int main() {
    scanf("%d%d", &n, &siz);
    
    f[0][0] = 1LL;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j <= i; j++)
            for(int k = 1; k <= j; k++)
                f[i][j] = (f[i][j] + f[i - k][min(j, i - k)]) % P;
    for(int i = n; i >= 1; i--)
        f[n][i] = (f[n][i] - f[n][i - 1] % P + P) % P;
        
/*    for(int i = 1; i <= n; i++)
        printf("%lld ", f[n][i]);
    printf("\n");   */
    
    ll ans = 0LL;
    for(int i = 1; i <= n; i++)
        for(int j = 1; j * i < siz && j <= n; j++)
            ans = (ans + f[n][i] * f[n][j] % P) % P;
    ans = ans * 2 % P;
    printf("%lld\n", ans);
    
    return 0;
}
View Code

 

posted @ 2018-08-22 14:24  CzxingcHen  阅读(241)  评论(0编辑  收藏  举报