qbzt day6 am

Merger or stones, but this can be any two merge and do the most and XOR

 

F [s] s represents the corresponding minimum cost for the combined gravel pile

Finally seeking f [2 ^ n-1]

How transfer?

The last time the two piles also merge into a pile, but there will be many cases, can enumerate all subsets s, handle sets and the rest merger

Direct enumerator smaller than s see if s | a = s or s & a = a

Complexity of O (4 ^ n)

Optimization: if they direct enumeration subset will be faster

cin >> n;
    for (int a=0;a<n;a++)
        cin >> z[a];
    for (int a=0;a<(1<<n);a++)
        for (int b=0;b<n;b++)
            if (a & (1<<b))
                sum[a] += z[b];
    
    memset(f,0x3f,sizeof(f));
    for (int a=0;a<n;a++)
        f[1<<a] = 0;
        
    /*for (int s=0;s<(1<<n);s++)
        for (int a=1;a<s;a++)
            if ( (s|a) == s)
                f[s] = min(f[s],f[a]+f[a^s]+(sum[a]^sum[a^s]));*/
                
    for (int s=0;s<(1<<n);s++)
        for (int a=(s-1)&s;a;a=(a-1)&s)
            f[s] = min(f[s],f[a]+f[a^s]+(sum[a]^sum[a^s]));
                
    cout << f[(1<<n)-1] << endl;

 

 

Complexity of O (3 ^ n)

Note that the enumeration method subset (very important)

 

Game Theory DP

 

There is a game G, two people play (van♂), turn-based, does not draw distinction between the outcome of the method is that when a person can not be operated when he lost

 

Example:

Have an integer S (2 <= S <= 200), the upper hand minus a number x in S, is at least 1, but less than S. After the two sides take turns to S subtract a positive integer, but can not exceed k times the number of the previous round each other to lose, the party reduced to 0 wins. He asked whether the upper hand to win?

How dp?

G has a lot of game state, if in a certain operation state, a state can transition to another state. If the status can not be transferred or are transferred to the winning state is terminated, this condition is called losing state means: Who is operated in this state, who will lose

Corresponding to the state can be transferred to the losing state is state win

f [s] a state representative of the game to win or be lost

If f is present [s [[i]] = false, there is f [s] = true if for all f [s [i]] = true, then f [s] = false

And what about? At present the rest of the team the last cut of the hand. f [i] [j] denotes the current remaining s i, Save opponent is a case where the win or losing j

Enumeration 1 <= r <= k * j, may be transferred to the f [ir] [r]

With memory search

#include<iostream>

using namespace std;

bool f[][],g[][];

bool dfs(int i,int j)
{
    if (i==0) return false;
    if (g[i][j]) return f[i][j];
    g[i][j]=true;f[i][j]=false;
    for (int r=1;r<=i && r<=k*j;r++)
        if (dfs(i-r,r) == false) f[i][j]=true;
    return f[i][j];
}

int main()
{
    cin >> s >> k;
    for (int a=1;a<s;a++)
        if (dfs(s-a,a) == false)
        {
            cout << "Alice" << endl;
            return 0;
        }
    cout << "Bob" << endl;
    
    return 0;
}

 

 

Now there are n games, how do?

Example: Take pebble game

N-stones piled, each can be removed from any number of stones inside a pile of stones. When there is no way anyone will get lost when the stones. Or losing the upper hand to win?

 

If there are only a pile of stones

SG function

Defined sg [0] = 0 sg [i]! = 0 represents a state i is a win sg [i] = 0 represents a state i is a losing

sg [1]: Find all state can be transferred to a 1, their function sg written down, find the smallest natural number there have been no

For sg [n], find the smallest no sg [0], sg [1] ... sg [n-1] in the number of natural occurring, this number is sg [n] value

sg function What is the use?

Return to this issue, we find sg function only to find a game, but the problem is more than a game, how to become a the n?

sg Theorem: sg game value n is equal to the value of each game sg XOR up

Proof: Take the first card

 

The question then push through the discovery sg [n] = n, so do just fine directly

 

int main()
{
    cin >> n;
    int ans=0;
    for (int a=1;a<=n;a++)
    {
        int v;
        cin >> v;
        ans = ans ^v;
    }
    if (ans!=0) cout << "Alice" << endl;
    else cout << "Bob" << endl;
}

 

 

例:给你n堆石子,每一次可以在某一堆石子中取走1~4个石子,问先手必胜还是必败

列出来sg函数找找规律,发现sg[i]=i%5,然后抑或起来就好了

 

一般这种题就是自己手算出sg函数然后抑或起来就好了

 

 

例:n+1堆石子,最左边一堆石头有2012个,两个人分别进行操作。一次操作可以选取两堆不同的石堆分别增加或减少一个石子(一加一减,或给已经不剩石子的堆加一个都是允许的)。为了保证游戏会在有限步内结束,规定所选的两堆中右边的那一堆一定要包含奇数个石子,无路可走者输.问先手是否必胜?

 

这个题非常恶心的一点就是不同的堆有联系,所以考虑把他转化成最基本的问题

先看每一堆是奇数个还是偶数个,答案就是把所有奇数的下标取出来异或,看是否等于0

有N堆石子放在N级楼梯上,楼梯编号为0..N-1,每堆有a[n]个石子。两人轮流游戏,每次将任意堆中的任意个石子移动到它下面那一层楼梯上,0号的石子不能动。直到所有石子都移动到0号,那个人就赢了。问先手是否有必胜策略 。

 

把所有下标为奇数的石子数量异或起来

因为如果把偶数位置的石子扔到奇数上,那么我只需要把奇数的位置移到下一个偶数就好了

所以偶数位置上的石子对答案没有影响,且奇数位置上的石子搬到偶数上后就没有影响了

例:N*M的棋盘,每个格子有一定数量棋子,每次可将某个格子部分或全部棋子向右或向下移动,问先手必胜还是必败。

 

和上个题差不多,只需要把所有距离为奇数的点的距离异或起来就行了

因为如果从偶数移动到奇数,一定可以从奇数移动到偶数,反之则不然

 

例:1xN(1<=N<=2000)的空格子,双方轮流操作,每次选一个没有被标记的格子,将其标记,如果某人操作完后,存在3个连续的格子都被标记了,那么他就获胜了,问先手是否有必胜策略?

 

如果把他当成一个游戏,我们需要搞一个2000位的二进制数,存都存不下

考虑把他当成多个游戏

如果我们先手在一个位置打标记,后手就不能在这个位置左两个右两个打标记

状态sg[i]表示对于一个长度为i的横条它的sg是多少

Vector存所有能转移到的sg值

枚举染色点,把原来的横条分成两个小的横条,算出来左边和右边的长度

怎么计算mex?

先排序,从0,1,2,3这样一直看,直到找到一个没有的。为了避免数组越界,直接加一个很大的数就可以了

#include<iostream>
#include<algorithm>
#include<vector>

using namespace std;

int dfs(int n)
{
    if (n==0) return 0;
    if (f[n]) return sg[n];
    f[n]=true;
    vector<int> z;
    for (int a=1;a<=n;a++)
    {
        int l = max(a-3,0);
        int r = max(n-a-2,0);
        z.push_back( dfs(l) ^ dfs(r) );
    }
    sort(z.begin(),z.end());
    z.push_back(233333333);
    
    for (int a=0,p=0;;a++)
    {
        if (z[p] != a)
        {
            sg[n] = a;
            return sg[n];
        }
        while (z[p]==a)
            p++;
    }
}

int main()
{
    cin >> n;
    if (dfs(n)) cout << "Alice" << endl;
    else cout << "Bob" << endl;
}

 

看看能不能有一种情况转移到必败态

但是开30000*30000的数组就炸了

怎么优化

把状态改成f[a][b][y],因为x只可能是2的倍数或者3的倍数

 

Guess you like

Origin www.cnblogs.com/lcezych/p/11206638.html