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

 

转载于:https://www.cnblogs.com/CzxingcHen/p/9517371.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值