CF 39E What Has Dirichlet Got to Do with That? (博弈)

博客介绍了CF 39E博弈问题的解决策略,当a ^ b达到或超过n时游戏结束。通过分析,发现n的范围限制了a和b的最大值。博主采用动态规划dp[i][j]来处理a > 1且b > 1的情况,并分别讨论了a等于1或b等于1时的特殊策略,包括平局和必败态的判断。最后处理a和b同时等于1的情况,确定先手玩家的胜负。

转载请注明出处,谢谢http://blog.youkuaiyun.com/ACM_cxlove?viewmode=contents    by---cxlove

题意:给出a ^ b,两个人轮流操作,可以  a + 1 也可以 b + 1,谁先使得a ^ b >= n则输。

由于题目给的n并不大,1e9的范围,如果不考虑a == 1 or b == 1的情况下

a最大为sqrt (n) ,b最大为ln(n) / ln(2)。

所以我们可以处理出所有的a > 1 && b > 1的情况,dp[i][j]表示当前局面为 i ^ j下的输赢情况,记忆化搜索一下。

然后便是考虑特殊情况

如果 a == 1 && b > 1,这种情况可能导致平局,便是两个轮流只在b上操作,导致结果一直为1。

那么我们可以模拟当前是否考虑操作a,由于a > 1 && b > 1所有情况的输赢已经处理过了。

所以只要当前a + 1 , b是个必败态,则会考虑操作。否则可能是平局。当然了a也是有个上限的。直接枚举模拟就行。


如果b == 1 && a > 1,这种情况下同理。

枚举模拟当前是否考虑操作b,如果a , b + 1是个必败态,那么会考虑操作。

我们可以处理到上界sqrt  (n),因为一旦 a > sqrt (n),只要操作b,便会失败。后面的局面就已经确定了。


如果 a == 1 && b == 1,先手操作a的话,便成了a > 1 && b == 1的局面,操作b的话便 成了a == 1 && b > 1的局面。

两种情况都处理一下,如果有必胜,肯定先手胜,否则如果有平局,则考虑平局,否则先手败。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <string>
#include <queue>
#include <cmath>
#include <algorithm>
#define Key_value ch[ch[root][1]][0]
using namespace std;
typedef long long LL;
const int N = 35000;
const int M = 31;
int a , b , n , dp[N][M];
// a ^ b >= n ? true : false
bool check (int a , int b , int n) {
    LL ret = 1LL;
    for (int i = 0 ; i < b ; i ++) {
        ret = ret * a;
        if (ret <= 0 || ret >= n) 
            return true;
    }
    return false;
}
int dfs (int a , int b) {
    if (dp[a][b] != -1) return dp[a][b];
    if (check (a , b , n)) {
        return dp[a][b] = 1;
    }
    int ret = 0;
    ret |= ! dfs (a + 1 , b);
    ret |= ! dfs (a , b + 1);
    return dp[a][b] = ret;
}
bool b_is_one (int a , int b = 1) {
    int up = sqrt (n - 0.0000001);
    int turn = 0;
    while (a <= up) {
        if (dp[a][b + 1] == 0) {
            return turn == 0;
        }
        a ++;turn = 1 - turn;
    }
    int remain = n - 1 - a;
    turn = (turn + remain) % 2;
    return turn;
}
int a_is_one (int b , int a = 1) {
    if (check (a , b , n)) return 0;
    else {
        int turn = 0;
        for ( ; !check (2 , b , n) ; b ++) {
            if (dp[a + 1][b] == 0) {
                if (turn == 0) return 1;
                else return -1;
            } 
            turn = 1 - turn;
        }
        return 0;
    }
}
int main () {
    #ifndef ONLINE_JUDGE
        freopen ("input.txt" , "r" , stdin);
        // freopen ("ouput.txt" , "w" , stdout);
    #endif
    memset (dp , -1 , sizeof (dp));
    cin >> a >> b >> n;
    if (check (a , b , n)) {
        puts ("Masha");
        return 0;
    }
    for (int i = 2 ; i < N ; i ++) {
        for (int j = 2 ; j < M ; j ++) {
            dp[i][j] = dfs (i , j);
        }
    }
    if (a !=1 && b != 1) {
        puts (dp[a][b] ? "Masha" : "Stas");
        return 0;
    }
    if (a == 1 && b == 1) {
        int c = a_is_one (b + 1) , d = b_is_one (a + 1);
        if (c < 0 || d == 0) puts ("Masha");
        else if (c == 0) puts ("Missing");
        else puts ("Stas");
    }
    else if (b == 1) {
        puts (b_is_one (a) ? "Masha" : "Stas");
    }
    else if (a == 1) {
        int c = a_is_one(b);
        if (c == 0) puts ("Missing");
        else if (c == 1) puts ("Masha");
        else puts ("Stas");
    }
    return 0;
}


LDA(Latent Dirichlet Allocation)主题模型中,**Dirichlet分布**在建模文档-主题分布和主题-单词分布时起到了核心作用。Dirichlet分布是一种定义在概率单纯形上的概率分布,通常用于生成一组离散的概率分布,这使其非常适合用于建模主题和词语的分布。 ### Dirichlet分布在LDA中的作用 1. **生成文档-主题分布**:LDA假设每篇文档由一个主题的混合分布表示,而这个混合分布是通过Dirichlet分布生成的。具体来说,对于每篇文档,LDA使用一个Dirichlet分布参数α(alpha)生成一个主题分布θ(theta)。该分布θ决定了文档中各个主题的权重,即文档中每个主题出现的概率 [^3]。 2. **生成主题-词语分布**:每个主题本身也是一个词语的分布,这个分布通过另一个Dirichlet分布参数η(eta)生成。对于每个主题k,LDA使用Dirichlet分布生成一个词语分布φ(phi),表示该主题下各个词语的概率分布 [^3]。 ### LDA生成主题的机制 LDA是一种生成式概率模型,其生成过程遵循以下步骤: 1. **为文档选择主题分布**:对于每篇文档d,从Dirichlet分布Dir(α)生成一个主题分布θ_d,表示文档d中各个主题的概率分布 [^3]。 2. **为主题选择词语分布**:对于每个主题k,从Dirichlet分布Dir(η)生成一个词语分布φ_k,表示主题k下各个词语的概率分布 [^3]。 3. **生成文档中的词语**: - 对文档中的每个词语n,从文档的主题分布θ_d中采样一个主题z_{d,n}。 - 然后,从该主题的词语分布φ_{z_{d,n}}中采样一个词语w_{d,n} [^2]。 这种生成过程使得LDA能够从文档集合中发现潜在的主题结构,并通过统计推断估计出每个文档的主题分布以及每个主题的词语分布。 ### Dirichlet分布对模型的影响 - **α参数**:α值较小会导致文档倾向于只包含少数几个主题,而α值较大则会使文档的主题分布更加均匀 。 - **η参数**:η值较小会导致主题倾向于只包含少数几个词语,而η值较大则会使主题的词语分布更加均匀 [^3]。 这些参数的选择对模型的效果有重要影响,因此在实际应用中,通常需要通过调参和评估模型的困惑度(perplexity)来优化这些参数 [^4]。 ### 示例代码 以下是一个使用`gensim`库训练LDA模型的示例代码: ```python from gensim.models import LdaModel from gensim.corpora import Dictionary # 假设data_set是已经预处理的文本数据 dictionary = Dictionary(data_set) # 构建词典 corpus = [dictionary.doc2bow(text) for text in data_set] # 生成文档-词频矩阵 # 训练LDA模型 lda = LdaModel( corpus=corpus, id2word=dictionary, num_topics=5, # 主题数量 passes=30, # 遍历语料库的次数 random_state=1 # 随机种子 ) # 输出每个主题的词语分布 topic_list = lda.print_topics() print(topic_list) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值