AtCoder ABC150

C题
签到题。会python的permutations 或者C++的next_permutation就能做。

D题
乍一看很简单,把所有元素折半求最小公倍数lcm,然后求lcm的奇数倍即可。但是有坑:
比如6 4这种情况,lcm=6 但6=61 6=41.5,因此无法满足要求。原因是4折半后为2,导致求得的lcm可以被2整除,如6/2不为半数。去掉这种情况就能AC。

# -*- 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(200050)


def gcd(x, y):
    if x > y:
        x, y = y, x
    while x:
        x, y = y % x, x
    return y


def main():
    items = sys.version.split()
    if items[0] == '3.10.6':
        fp = open("in.txt")
    else:
        fp = sys.stdin
    n, m = map(int, fp.readline().split())
    a = list(map(int, fp.readline().split()))
    for i in range(n):
        a[i] = a[i] // 2
    gm = a[0]
    for i in range(1, n):
        g = gcd(a[i], gm)
        gm = gm // g * a[i]

    for i in range(n):
        if (gm // a[i]) % 2 == 0:
            print(0)
            return

    ans = m // gm - (m // (2 * gm))
    print(ans)


if __name__ == "__main__":
    main()

E题
下面两个很不错的题。
本题考察如何按位置来计数。首先题目可以把 f ( S , T ) f(S,T) f(S,T)转换为求 f ( S ) = S ⊕ T f(S)=S \oplus T f(S)=ST下按照原规则计算,然后答案乘上 2 n 2^n 2n
如 第二个例子中 5 8
可以看到以下 2 2 2^2 22组是等价的
( 1 , 0 ) , ( 0 , 0 ) (1,0) ,(0,0) (1,0),(0,0)
( 0 , 0 ) , ( 1 , 0 ) (0,0),(1,0) (0,0),(1,0)
( 1 , 1 ) , ( 0 , 1 ) (1,1),(0,1) (1,1),(0,1)
( 1 , 0 ) , ( 0 , 0 ) (1,0),(0,0) (1,0),(0,0)
现在原题就转换为求 s ∈ 0... 2 n s \in {0...2^n} s0...2n f ( s ) f(s) f(s)之和。
显然c应该从大到小排序。

如果按照每个c从第一位到第n位来计数,那么不难利用组合数推出一个 O ( n 2 ) O(n^2) O(n2)算法。但是时间不够。

比较巧妙的计数方法是将每一位的计算拆开来。
假设当前已经到了第i位(i从1开始计数)
例如要求的c数组长度为3,可以列出8个异或值。
1 , 1 , 1 1 , 0 , 0 1 , 0 , 1 1 , 1 , 0 0 , 0 , 0 0 , 0 , 1 0 , 1 , 0 0 , 1 , 1 1,1,1\\1,0,0\\1,0,1\\1,1,0\\0,0,0\\0,0,1\\0,1,0\\0,1,1 1,1,11,0,01,0,11,1,00,0,00,0,10,1,00,1,1
看第3位,他对答案的贡献是3+2+1+2=8(从上往下)
我们可以将其拆成两部分,第一部分是“只要填了1就可以贡献1”
由于这部分和其他无关,因此贡献值一共为 2 n − 1 2^{n-1} 2n1
第二部分是“前面的某一位填了1因此要多贡献1”
这部分仅仅和前面的那一位相关(当然这一位也要填1),因此贡献值是 2 n − 2 ∗ ( i − 1 ) 2^{n-2}*(i-1) 2n2(i1)
这样答案就已经出来了。
回到样例,例如第一组 1 , 1 , 1 1,1,1 1,1,1中,第一部分贡献1,第二部分分别由前面的数字贡献了1+1,因此是3;第三组 1 , 0 , 1 1,0,1 1,0,1中,第一部分贡献1,第二部分由第一位1贡献了1,因此是2.

# -*- 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(200050)


def main():
    items = sys.version.split()
    if items[0] == '3.10.6':
        fp = open("in.txt")
    else:
        fp = sys.stdin
    n = int(fp.readline())
    a = list(map(int, fp.readline().split()))
    a.sort(reverse=True)
    mod = 10 ** 9 + 7

    pw = [1] * (n + 1)
    for i in range(1, n + 1):
        pw[i] = pw[i - 1] * 2 % mod

    ans = 0
    for i in range(n):
        ans += (pw[n - 1] + pw[n - 2] * i) * a[i]
    ans = ans * pw[n] % mod
    print(ans)


if __name__ == "__main__":
    main()

F题
看到这种求shift的题,第一感觉一定是将匹配串重复一遍。
好吧,既然说到了模式串和匹配串,那么不得不说到kmp。单纯的kmp似乎没什么思路,但是如果将每个数组相邻的数进行异或操作,就变成了kmp模板题。

# -*- 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 get_next(p):
    p = [0] + list(p)
    m = len(p)
    ne = [0] * m
    i, j = 2, 0
    while i < m:
        while j and p[i] != p[j + 1]:
            j = ne[j]
        if p[i] == p[j + 1]:
            j += 1
        ne[i] = j
        i += 1
    return ne


def kmp_match(s, p, ne):
    s = [0] + list(s)
    p_len = len(p)
    p = [0] + list(p)
    i, j = 1, 0
    n, m = len(s), len(p)
    m_list = []
    while i < n:
        while j and j + 1 < m and s[i] != p[j + 1]:
            j = ne[j]
        if j + 1 < m and s[i] == p[j + 1]:
            j += 1
        if j == p_len:
            bi, ei = i - p_len + 1, i
            j = ne[j]
            m_list.append(bi - 1)
        i += 1
    return m_list


def main():
    items = sys.version.split()
    if items[0] == '3.10.6':
        fp = open("in.txt")
    else:
        fp = sys.stdin
    n = int(fp.readline())
    a = list(map(int, fp.readline().split()))
    b = list(map(int, fp.readline().split()))
    a = a + a
    da, db = [], []
    for i in range(2 * n - 2):
        da.append(a[i + 1] ^ a[i])
    for i in range(n - 1):
        db.append(b[i + 1] ^ b[i])
    ne = get_next(db)
    m_list = kmp_match(da, db, ne)
    for i in m_list:
        print(i, a[i] ^ b[0])


if __name__ == "__main__":
    main()

你可能感兴趣的:(Atcoder,Atcoder)