Atcoder Tenka1 Programmer Contest 2019 D Three Colors

题意:
\(n\)个石头,每个石头有权值,可以给它们染'R', 'G', 'B'三种颜色,如下定义一种染色方案为合法方案:

  • 所有石头都染上了一种颜色
  • \(R, G, B\)为染了'R', 染了'G', 染了'B'的所有石头的权值和,存在一个三角形的三边为\(R, G, B\)

求合法方案数模\(998244353\)

思路:
考虑总方案数为\(3^n\),我们考虑怎么求出不合法的方案数。令\(dp[i][j]\)表示到第\(i\)个石头,两条短边和为\(j\)的方案数
但是我们注意到,如果\(sum\)是偶数的话,那么:

  1. \(R = B = \frac{sum}{2}\)\(B = R = \frac{sum}{2}\)
  2. \(R = G = \frac{sum}{2}\)\(G = R = \frac{sum}{2}\)
  3. \(B = G = \frac{sum}{2}\)\(G = B = \frac{sum}{2}\)

贡献会重复算一遍,再\(dp\)一次,删掉一份贡献即可。

代码:

#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define N 310
const ll p = 998244353; 
int n, a[N];
ll f[N * N], g[N * N], all;

int main() {
    while (scanf("%d", &n) != EOF) {
        ll sum = 0, mid;
        all = 1;
        for (int i = 1; i <= n; ++i) {
            scanf("%d", a + i);
            sum += a[i];    
            all = (all * 3) % p; 
        }
        mid = sum / 2;  
        memset(f, 0, sizeof f);  
        f[0] = 1;   
        for (int i = 1; i <= n; ++i) {
            for (int j = sum - a[i]; j >= 0; --j) {
                f[j + a[i]] = (f[j + a[i]] + f[j] * 2 % p) % p;  
            }        
        }
        
        ll res = 0; 
        for (int i = 0; i <= mid; ++i) {      
            res = (res + f[i]) % p;
        }
        if (sum % 2 == 0) {
            memset(g, 0, sizeof g);
            g[0] = 1;
            for (int i = 1; i <= n; ++i) {
                for (int j = sum - a[i]; j >= 0; --j) {
                    g[j + a[i]] = (g[j + a[i]] + g[j]) % p;
                }
            }
            res = (res - g[mid] + p) % p;    
        }
        printf("%lld\n", (all - (res * 3) % p + p) % p); 
    }
    return 0;
}

转载于:https://www.cnblogs.com/Dup4/p/10750105.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值