1. 程式人生 > 其它 >HDU-2188 悼念512汶川大地震遇難同胞――選拔志願者

HDU-2188 悼念512汶川大地震遇難同胞――選拔志願者

悼念512汶川大地震遇難同胞――選拔志願者

巴什博奕

拿到題想了老半天,感覺能超出 n 資金是個坑點,一直想不明白,就暴力打了個表,然後發現複雜度能過就交了,然後過了

後來分析發現“能超出 n 資金”這一條件完全是可有可無

  • 如果當前 n mod (m + 1) = 0:

可以直接確定先手必輸,因為後手只要控制好每次都是在 n mod (m + 1) = 0 就行

  • 如果當前 n mod (m + 1) != 0:

先手可以將其轉換為第一種情況

所以根據以上分析,先手必勝方完全沒有必要將石子改到 n 以上

打表的方式:

#include <iostream>
using namespace std;
const int maxn = 1e5 + 20;
int sg[maxn], vis[maxn];

void get_sg(int n, int m)
{
    for(int i=0; i<=n; i++) sg[i] = 0;
    for(int i=1; i<=n; i++)
    {
        for(int j=0; j<=m; j++) vis[j] = 0;
        for(int j=max(0, i-m); j<i; j++)
            vis[sg[j]] = 1;
        for(int j=0; j<maxn; j++)
        {
            if(vis[j] == 0)
            {
                sg[i] = j;
                break;
            }
        }
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while(t--)
    {
        int n, m;
        cin >> n >> m;
        get_sg(n, m);
        // for(int i=0; i<=n; i++) cout << i << " sg: " << sg[i] << endl;
        bool flag = sg[n] != 0;
        for(int i=max(0, n - m); !flag && i<n; i++)
            if(sg[i] == 0) flag = true;
        if(flag) cout << "Grass" << endl;
        else cout << "Rabbit" << endl;
    }
    return 0;
}

直接取餘分析:

#include <iostream>
using namespace std;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while(t--)
    {
        int n, m;
        cin >> n >> m;
        if(n % (m + 1) == 0) cout << "Rabbit" << endl;
        else cout << "Grass" << endl;
    }
    return 0;
}