Задать вопрос
@alex_agaphe

Какие переходы для ДП у «Гелифиш и незабудка» codeforce?

https://codeforces.com/contest/2115/problem/D
Гелифиш и Флауэр играют в игру.

Игра состоит из двух массивов из n
целых чисел a1,a2,…,an
и b1,b2,…,bn
, а также бинарной строки c1c2…cn
длиной n
.

Также есть целое число x
, которое инициализируется значением 0
.

Игра состоит из n
раундов. Для i=1,2,…,n
раунд проходит следующим образом:

Если ci=0
, активным игроком будет Гелифиш. В противном случае, если ci=1
, активным игроком будет Флауэр.
Активный игрок выполнит ровно одну из следующих операций:
Присвоить x:=x⊕ai
.
Присвоить x:=x⊕bi
.
Здесь ⊕
обозначает операцию побитового исключающего ИЛИ.

Гелифиш хочет минимизировать итоговое значение x
после n
раундов, в то время как Флауэр хочет максимизировать его.

Найдите итоговое значение x
после всех n
раундов, если оба игрока играют оптимально.


Моя идея - задать начальное значнеие как xor сумму. и на каждом шаге решать включать ли b[i] вместо a[i] или нет.
Была идея включать дп перебирать посуффиксм для различныз range но она несраотало.
_max=sum(a)+sum(b)
    _dp = [[0 for _ in range(2*_max+1)] for _ in range(n+1)]
    for i in range(_max+1):
            _dp[-1][i^a[i]] = a[-1] ^ i
            _dp[-1][i^b[i]] = b[-1] ^ i
    for i in range(n-1, -1, -1):
        for j in range(_max+1):
            if c[i]==1:
                _dp[i][j]=max(_dp[i+1][j^b[i]], _dp[i+1][j^a[i]])
            else:
                _dp[i][j]=min(_dp[i+1][j^b[i]], _dp[i+1][j^a[i]])
    return max(_dp[0]) if c[0]==1 else min(_dp[0])


Текущая идея - задать начальное значнеие как xor сумму. и на каждом шаге решать включать ли b[i] вместо a[i] или нет.

def _eval_r(a: list, b: list, c:list, n:int):
    x=reduce(lambda x,y: x^y, a)
    b=[b[i]^a[i] for i in range(n)]
    for i in range(n-1, -1, -1):
        new_x=x^b[i]
        if c[i]==1 and new_x>x:
            x=new_x
        elif new_x<x:
            x=new_x
    return x


t=int(input())
for _ in range(t):
    _=input()
    a=[int(x) for x in input().split()]
    b=[int(x) for x in input().split()]
    c=[int(x) for x in input()]
    print(_eval_r(a, b, c, len(a)))
  • Вопрос задан
  • 48 просмотров
Подписаться 1 Средний Комментировать
Пригласить эксперта
Ответы на вопрос 1
wataru
@wataru Куратор тега Алгоритмы
Разработчик на С++, экс-олимпиадник.
Не вижу, где тут ДП.

Вы правильно заметили, что можно вместо ai и bi рассматривать только ai^bi. Мы как будто берем все A по дефолту и каждый игрок может своим решением это стандартное действие отменить, что равносильно брать или не брать ai^bi.

Но надо заметить еще одно важное свойство (пусть di = ai ^ bi). Любое di можно заменть на di^dj (j > i) и задача остается эквивалентной. Тут каждый игрок вместо решения брать или не брать dj в зависимсоти от текущей суммы, он будет решать. делать ли статус у dj таким же как у di или нет. Ну или, рассуждение как выше, стандартное действие - брать dj если di было взято. Каждый игрок может своим решением это действие отменить.

А это уже очень похоже на вычитание линейных уравнений друг из друга в методе гауса. Можно этим заняться и привести Di к виду, где для каждого разряда мы найдем "базисный вектор" и единица будет стоять только в нем, а во всех остальных числах на этом разряде будет стоять 0. Для каких-то разядов мы может такого не найдем, там может быть много единиц, но все они будут в базисных векторах для каких-то других разрядов. При чем начинайте фиксировать базис с максимальных разрядов. Тогда у вас будут какие-то базисные разряды, и не базисные, которые однозначно определяются базисными и меньше их.

Т.е. идете с конца по массиву D, из текущего числа xor-ите все базисные вектора. если стоит единица в нужном разряде. Если там остался не ноль, добавляете это число в базис для старшего бита.

И тут уже сразу ясно, надо ли какое-то Di брать или нет. Каждый игрок знает, хочет ли он этот разряд в конце сделать 1 или 0 (в зависимости от его цели и того, стоит ли 1 в xor всех A в этом разряде).

Вот и все. Никакого ДП.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы