Atcoder ABC159

总体来说本期比较简单

C - Maximum Volume
答案显然是 O ( N 3 ) O(N^3) O(N3)

D - Banned K
先统计总的,然后减去选到的那个数再重新计算

E - Dividing Chocolate
既然n范围是10,那么在n的宽度上做一个位操作,若i位与i+1位之间有切割,i位设为1,枚举横方向的切割方案,然后在竖方向上做贪心

# -*- coding: utf-8 -*-
# @time     : 2023/6/2 13:30
# @file     : atcoder.py
# @software : PyCharm

import bisect
import copy
import sys
from itertools import permutations
from sortedcontainers import SortedList
from collections import defaultdict, Counter, deque
from functools import lru_cache, cmp_to_key
import heapq
import math
sys.setrecursionlimit(1000)


def main():
    items = sys.version.split()
    if items[0] == '3.10.6':
        fp = open("in.txt")
    else:
        fp = sys.stdin
    n, m, K = map(int, fp.readline().split())
    a = []
    for i in range(n):
        s = fp.readline().strip()
        a.append(s)
    sm = [[0] * m for _ in range(n + 1)]
    for j in range(m):
        for i in range(n):
            sm[i + 1][j] = sm[i][j] + ord(a[i][j]) - ord('0')

    ans = 10 ** 18
    for mask in range(1 << (n - 1)):
        last = 0
        temp = []
        div_cnt = 0
        ac = 1
        for j in range(n):
            if mask >> j & 1 or j == n - 1:
                b = []
                for k in range(m):
                    x = sm[j + 1][k] - sm[last][k]
                    if x > K:
                        ac = 0
                    b.append(x)
                last = j + 1
                temp.append(b)
            if mask >> j & 1:
                div_cnt += 1
        if ac == 0:
            continue
        l = len(temp)
        t = [0] * l
        for j in range(m):
            d = 0
            for i in range(l):
                t[i] += temp[i][j]
                if t[i] > K:
                    d = 1
            if d:
                div_cnt += 1
                for i in range(l):
                    t[i] = temp[i][j]
        ans = min(ans, div_cnt)
    print(ans)


if __name__ == "__main__":
    main()

F - Knapsack for All Segments

观察了一下,发现在做到 i位时,可以去计算 F ( i , s u m ) F(i, sum) F(i,sum)
其中sum是当前计算的和,F代表方案数
F ( i , s u m ) = ∑ F ( j , s u m − a [ i ] ) ∗ ( n − i ) F(i,sum)=\sum F(j,sum-a[i])*(n-i) F(i,sum)=F(j,suma[i])(ni)
但是这样是 O ( N 2 ∗ S ) O(N^2*S) O(N2S)的三重循环,因此要记录一下前缀和 G ( s u m ) = ∑ F ( i , s u m ) G(sum)=\sum F(i,sum) G(sum)=F(i,sum)

# -*- coding: utf-8 -*-
# @time     : 2023/6/2 13:30
# @file     : atcoder.py
# @software : PyCharm

import bisect
import copy
import sys
from itertools import permutations
from sortedcontainers import SortedList
from collections import defaultdict, Counter, deque
from functools import lru_cache, cmp_to_key
import heapq
import math
sys.setrecursionlimit(1000)


def main():
    items = sys.version.split()
    if items[0] == '3.10.6':
        fp = open("in.txt")
    else:
        fp = sys.stdin
    n, S = map(int, fp.readline().split())
    a = list(map(int, fp.readline().split()))
    dp = [0] * (S + 1)
    mod = 998244353
    ans = 0
    for i in range(n):
        if a[i] == S:
            ans += (i + 1) * (n - i)
            ans %= mod
        elif S - a[i] > 0:
            ans += dp[S - a[i]] * (n - i)
            ans %= mod
            for j in range(S, -1, -1):
                if j >= a[i]:
                    dp[j] = (dp[j] + dp[j - a[i]]) % mod
            dp[a[i]] += i + 1
            dp[a[i]] %= mod
    print(ans)


if __name__ == "__main__":
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值