zoukankan      html  css  js  c++  java
  • bzoj4600 [Sdoi2016]硬币游戏

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4600

    【题解】

    显然可以发现对于每个c,互相独立。

    博弈问题,考虑sg函数。

    预处理出每个数的2的因数个数t2[i],3的因数个数t3[i]

    对于这一次能翻的硬币,记忆化搞搞sg值,然后异或起来即可。

    sg函数非常神奇啊qwq

    这题你进去会发现 一个状态的后继状态是由好几个硬币构成的,那么把他们异或起来就行了!

    # include <stdio.h>
    # include <string.h>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int M = 3e4 + 10, N = 20;
    const int mod = 1e9+7;
    
    # define RG register
    # define ST static
    
    int n, m, t2[M], t3[M]; 
    
    int sg[N][N];
    bool vis[N][N]; 
    inline int getsg(int x, int y) {
        if(vis[x][y]) return sg[x][y];
        vis[x][y] = 1;
        int SG; 
        bool g[62]; memset(g, 0, sizeof g);  
        for (int q=1; q<=m; ++q) {
            for (int p=1; p*q<=x; ++p) {
                int s = 0; bool hv = 0;
                for (int j=0; j<=q; ++j) {
                    if(!hv) hv = 1; 
                    s = s ^ getsg(x-p*j, y);
                }
                if(hv) g[s] = 1; 
            }
        }
        for (int q=1; q<=m; ++q) {
            for (int p=1; p*q<=y; ++p) {
                int s = 0; bool hv = 0;
                for (int j=0; j<=q; ++j) {
                    if(!hv) hv = 1; 
                    s = s ^ getsg(x, y-p*j);
                }
                if(hv) g[s] = 1; 
            }
        }    
        for (int i=0; i<=60; ++i) 
            if(!g[i]) {
                SG = i;
                break;
            }
        return sg[x][y] = SG; 
    }
    
    inline void sol() {
        memset(vis, 0, sizeof vis);
        memset(sg, 0, sizeof sg); 
        scanf("%d%d", &n, &m);
        int ans = 0;
        for (int i=1, t; i<=n; ++i) {
            scanf("%d", &t);
            if(t) continue;
            ans ^= getsg(t2[i], t3[i]); 
        }
        if(ans) puts("win");
        else puts("lose");
    }
    
    int main() {
        for (int i=1; i<=30000; ++i) {
            int t = i;
            while(t%2 == 0) t2[i] ++, t/=2;
            while(t%3 == 0) t3[i] ++, t/=3;
        }
        int T; scanf("%d", &T);
        while(T--) sol(); 
        return 0;
    }
    View Code
  • 相关阅读:
    第三周学习进度总结
    第二周学习进度总结
    动手动脑04
    动手动脑03
    动手动脑02
    课堂实践总结
    课堂实践
    原码,反码和补码学习报告
    开学第一周
    第八周
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj4600.html
Copyright © 2011-2022 走看看