LibreOJ #528. 「LibreOJ β Round #4」求和

本文介绍了一道名为“LibreOJ#528.「LibreOJβRound#4」求和”的算法题目,通过分析问题本质为寻找特定条件下整数对的数量,并利用容斥原理和莫比乌斯函数解决重复计数问题。

二次联通门 : LibreOJ #528. 「LibreOJ β Round #4」求和

 

 

 

 

 

/*
    LibreOJ #528. 「LibreOJ β Round #4」求和
    
    题目要求的是有多少对数满足他们的最大公约数的质因子不超过一个
    f (x) 表示有多少对数满足最大公约数中含有x^2这个因子
    那么f (x) = N / x ^ 2 * M * (x ^ 2)
    答案即为所有数字减去不符合要求的数字个数

    但是我们发现,可能某对数字的最大公约数含有多个质数平方因子
    那么在处理的时候就会重复筛去

    这时我们可以用容斥原理,用μ来作为容斥系数
    枚举x即可
*/
#include <cstdio>
#include <iostream>
#include <cmath>

#define Max 3231231
inline long long min (long long a, long long b) { return a < b ? a : b; }
int mu[Max | 1], is[Max | 1], p[Max | 1];
#define Mod 998244353

int Main ()
{
    long long N, M; scanf ("%lld%lld", &N, &M); register int i, j;
    int Answer = 0; int C = 0;
    int Limit = min (sqrt (N), sqrt (M));
    for (i = 2, is[1] = true, mu[1] = 1; i <= Max; ++ i)
    {
        if (!is[i]) p[++ C] = i, mu[i] = -1;
        for (j = 1; j <= C && i * p[j] <= Max; ++ j)
        {
            is[i * p[j]] = true; if (i % p[j] == 0) break;
            mu[i * p[j]] = -mu[i];    
        }
    }
    for (i = 1; i <= Limit; ++ i)
        Answer = (Answer + mu[i] * (N / (1LL * i * i) % Mod) * (M / (1LL * i * i) % Mod) % Mod + Mod) % Mod;
    printf ("%d", Answer);
    return 0;
}
int ZlycerQan = Main ();
int main (int argc, char *argv[]) {;}

 

转载于:https://www.cnblogs.com/ZlycerQan/p/7470078.html

<think>我们正在实现麻将AI决策流程中的花色权重分析功能。根据之前的讨论,花色权重分析模块需要考虑四川麻将的缺一门规则,并动态计算各花色的权重。权重公式如下: $$ W_f = \begin{cases} 0 & \text{若 } f \text{ 为缺失花色} \\ \alpha \cdot \frac{N_f}{N_{\text{total}}} + \beta \cdot P_{\text{win}}^f & \text{否则} \end{cases} $$ 其中: - $f$ 表示花色(万、筒、条) - $N_f$ 是当前手牌中花色$f$的牌数 - $N_{\text{total}}$ 是当前手牌总牌数(通常为13张,但可能因阶段而异) - $P_{\text{win}}^f$ 是保留该花色牌时的胡牌概率(需要估算) - $\alpha$ 和 $\beta$ 是攻防平衡系数(默认值分别为0.6和0.4### 实现步骤 1. **确定缺失花色**:根据四川麻将规则,玩家必须缺一门花色(即不能有三种花色)。通常,在游戏开始时会确定缺失花色,但AI也可以根据当前手牌和已出牌情况动态调整策略。这里我们假设缺失花色已经确定(作为输入)。 2. **计算各花色牌的数量**:遍历手牌,统计每个花色的牌数。 3. **估算胡牌概率**:这部分比较复杂,我们可以先使用一个简化版本来估算。简化思路: - 对于每个非缺失花色,计算该花色形成有效组合(刻子、顺子)的潜力。 - 根据该花色已有的牌和剩余牌的数量,估算其完成面子的概率。 - 注意:完整的胡牌概率计算需要递归或动态规划,这里我们先使用一个启发式方法:用该花色当前牌数占该花色总牌数的比例来近似,或者使用预定义的表格。 4. **计算权重**:对于非缺失花色,按照公式计算权重。 ### 代码实现 我们将编写一个函数`analyze_colors(hand, missing_suit, alpha=0.6, beta=0.4)`,其中: - `hand`:当前手牌,是一个列表,每个元素是一个字符串,如"3万"、"5筒"、"7条"。 - `missing_suit`:缺失的花色,用字符串表示,如"万"、"筒"、"条"。 - `alpha`和`beta`:攻防平衡系数。 返回一个字典,包含三个花色的权重(缺失花色的权重为0)。 ### 简化胡牌概率估算 由于精确计算胡牌概率非常复杂,我们这里采用一个简化方法: - 对于每个花色,我们计算该花色在整副牌中的剩余牌数(假设初始为36张,因为每种花色有9种牌,每种4张,共36张),然后减去已经出现的牌(包括手牌和已经打出的牌)。但是,由于我们目前只有手牌信息,为了简化,我们只考虑手牌中该花色的数量,并假设剩余牌是均匀分布的。 - 我们使用一个经验公式:$P_{\text{win}}^f \approx \frac{N_f}{4}$(因为每张牌有4张,所以当$N_f$达到4时,该花色的牌足够多,胡牌概率就高)。但这样显然不够准确,我们可以改进为:$P_{\text{win}}^f \approx \min(1, \frac{N_f}{4} \times 0.5 + \frac{N_f}{9} \times 0.5)$,这个公式结合了牌的数量和该花色的牌型潜力(9种牌)。但请注意,这只是一个非常粗略的估计。 在实际应用中,我们可以使用预先训练的概率表或者更复杂的模型。但为了本功能的实现,我们采用以下简化: $$ P_{\text{win}}^f = \min\left(1, \frac{N_f}{12}\right) $$ 因为一般来说,一个花色有12张牌(包括手牌和后续摸到的)就很容易形成组合。当然,这个简化并不科学,但作为示例,我们先这样实现。 ### 代码 ```python def analyze_colors(hand, missing_suit, alpha=0.6, beta=0.4): """ 分析手牌中各花色的权重 :param hand: 当前手牌,例如: [&#39;1万&#39;, &#39;2万&#39;, &#39;3万&#39;, &#39;4筒&#39;, &#39;5筒&#39;, &#39;6条&#39;, &#39;7条&#39;] :param missing_suit: 缺失的花色,例如: &#39;万&#39; :param alpha: 攻防平衡系数,用于数量比例 :param beta: 攻防平衡系数,用于胡牌概率 :return: 字典,包含三个花色的权重,例如: {&#39;万&#39;: 0, &#39;筒&#39;: 0.65, &#39;条&#39;: 0.78} """ # 初始化三个花色 suits = [&#39;万&#39;, &#39;筒&#39;, &#39;条&#39;] # 统计每个花色的牌数 suit_count = {suit: 0 for suit in suits} for tile in hand: # 每张牌的最后一个字符是花色 suit = tile[-1] if suit in suit_count: suit_count[suit] += 1 total_tiles = len(hand) weights = {} for suit in suits: if suit == missing_suit: weights[suit] = 0.0 else: count = suit_count[suit] # 计算数量比例 ratio = count / total_tiles if total_tiles > 0 else 0 # 估算胡牌概率(简化版) win_prob = min(1.0, count / 12.0) # 简化估计 # 计算权重 weights[suit] = alpha * ratio + beta * win_prob return weights ``` ### 测试 ```python # 测试用例 hand = [&#39;1万&#39;, &#39;2万&#39;, &#39;3万&#39;, &#39;4筒&#39;, &#39;5筒&#39;, &#39;6筒&#39;, &#39;7条&#39;] missing_suit = &#39;万&#39; # 缺万 weights = analyze_colors(hand, missing_suit) print(weights) # 预期:万:0, 筒和条有权重 ``` ### 说明 1. 这个简化版本没有考虑已经打出的牌和对手的手牌,因此胡牌概率的估计非常粗略。 2. 在实际应用中,`P_win^f`应该通过更复杂的模型(如基于概率表、机器学习模型或蒙特卡洛模拟)来估算。 ### 改进方向 1. 可以引入剩余牌的信息,从而更准确地估算胡牌概率。 2. 考虑花色的组合潜力,比如该花色是否容易形成顺子(如相邻牌的数量)或刻子。 ### 相关问题 1. 如何更精确地估算麻将AI中的胡牌概率? 2. 花色权重分析中如何考虑对手的弃牌信息? 3. 在动态调整攻防平衡系数(alpha和beta)时,有哪些策略?</think># 麻将AI花色权重分析功能实现 根据四川麻将规则和决策优化需求,我将实现麻将AI决策流程中的花色权重分析功能。核心功能是动态计算各花色权重,帮助AI做出最优决策。 ## 实现方案 ```python class ColorAnalyzer: def __init__(self, hand, discarded_tiles, round_stage): """ 花色权重分析器 :param hand: 当前手牌列表,如["1万", "2万", "3筒", "4条"] :param discarded_tiles: 已弃牌列表 :param round_stage: 牌局阶段(0-1),0=早期,1=晚期 """ self.hand = hand self.discarded_tiles = discarded_tiles self.round_stage = round_stage self.suits = [&#39;万&#39;, &#39;筒&#39;, &#39;条&#39;] # 四川麻将三种花色 def analyze_colors(self): """主分析函数:计算各花色权重""" # 1. 确定缺失花色 missing_suit = self._determine_missing_suit() # 2. 计算各花色权重 weights = {} for suit in self.suits: if suit == missing_suit: weights[suit] = 0.0 # 缺失花色权重为0 else: weights[suit] = self._calculate_suit_weight(suit) return weights, missing_suit def _determine_missing_suit(self): """确定缺失花色(根据手牌数量最少的花色)""" suit_counts = {suit: 0 for suit in self.suits} for tile in self.hand: for suit in self.suits: if suit in tile: suit_counts[suit] += 1 return min(suit_counts, key=suit_counts.get) def _calculate_suit_weight(self, suit): """计算单个花色权重""" # 计算该花色牌的数量和比例 suit_tiles = [t for t in self.hand if suit in t] suit_count = len(suit_tiles) total_tiles = len(self.hand) suit_ratio = suit_count / total_tiles if total_tiles > 0 else 0 # 估算胡牌概率(简化版) win_prob = self._estimate_win_probability(suit, suit_count) # 动态调整攻防平衡系数 alpha, beta = self._adjust_balance_coefficients() # 计算最终权重 return alpha * suit_ratio + beta * win_prob def _estimate_win_probability(self, suit, suit_count): """ 估算该花色的胡牌概率(简化版) 实际应用中应使用更精确的概率模型[^1] """ # 基础概率:基于该花色牌的数量 base_prob = min(1.0, suit_count / 8.0) # 8张牌可组成2个面子+将牌 # 调整因子:考虑该花色的安全性和潜力 safety_factor = self._calculate_safety_factor(suit) potential_factor = self._calculate_potential_factor(suit) return base_prob * safety_factor * potential_factor def _calculate_safety_factor(self, suit): """计算安全系数:基于该花色在弃牌中的比例""" total_discarded = len(self.discarded_tiles) if total_discarded == 0: return 1.0 suit_discarded = sum(1 for t in self.discarded_tiles if suit in t) discard_ratio = suit_discarded / total_discarded # 弃牌率越高,安全系数越高 return min(1.0, discard_ratio * 1.5) # 放大安全系数 def _calculate_potential_factor(self, suit): """计算潜力系数:评估该花色形成组合的潜力""" # 获取该花色所有牌的数字 suit_numbers = [int(t[0]) for t in self.hand if suit in t] if not suit_numbers: return 0.5 # 无牌时默认值 # 计算形成顺子/刻子的潜力 potential = 0 # 刻子潜力:相同数字的牌 from collections import Counter num_counts = Counter(suit_numbers) for count in num_counts.values(): if count >= 2: # 有对子或更多 potential += 0.2 * min(count, 3) # 最多0.6 # 顺子潜力:连续数字的牌 sorted_nums = sorted(set(suit_numbers)) for i in range(len(sorted_nums) - 1): diff = sorted_nums[i+1] - sorted_nums[i] if diff == 1: # 连续 potential += 0.15 elif diff == 2: # 间隔1 potential += 0.1 return min(1.0, 0.5 + potential) # 基础0.5 + 潜力值 def _adjust_balance_coefficients(self): """动态调整攻防平衡系数α和β""" # 基础系数 alpha = 0.6 # 数量比例权重 beta = 0.4 # 胡牌概率权重 # 根据牌局阶段调整:晚期更注重胡牌概率 if self.round_stage > 0.7: # 晚期阶段 alpha -= 0.2 * self.round_stage beta += 0.2 * self.round_stage # 根据手牌进攻性调整(简化) if len(self.hand) < 10: # 手牌较少时更注重胡牌 alpha = max(0.4, alpha - 0.1) beta = min(0.6, beta + 0.1) return max(0.1, alpha), max(0.1, beta) ``` ## 使用示例 ```python # 示例数据 hand = ["1万", "2万", "3万", "4筒", "5筒", "6筒", "7条", "8条"] discarded = ["3万", "4万", "5条", "6条"] round_stage = 0.4 # 中期阶段 # 创建分析器 analyzer = ColorAnalyzer(hand, discarded, round_stage) # 执行分析 weights, missing_suit = analyzer.analyze_colors() print(f"缺失花色: {missing_suit}") print("花色权重:") for suit, weight in weights.items(): print(f"{suit}: {weight:.3f}") ``` ## 关键算法说明 ### 1. 缺失花色确定 使用最小牌数原则确定缺失花色: $$ \text{missing\_suit} = \argmin_{s \in \{\text{万}, \text{筒}, \text{条}\}} |H_s| $$ 其中 $H_s$ 是手牌中花色 $s$ 的牌数 ### 2. 花色权重计算 对于非缺失花色,权重计算公式为: $$ W_f = \alpha \cdot \frac{|H_f|}{|H|} + \beta \cdot P_{\text{win}}^f $$ 其中: - $\alpha$ 和 $\beta$ 是动态调整的攻防平衡系数 - $|H_f|$ 是该花色牌的数量 - $|H|$ 是手牌总数 - $P_{\text{win}}^f$ 是该花色的胡牌概率估计值 ### 3. 胡牌概率估计 使用多因子模型简化计算: $$ P_{\text{win}}^f = \underbrace{\min\left(1, \frac{|H_f|}{8}\right)}_{\text{基础概率}} \times \underbrace{S_f}_{\text{安全系数}} \times \underbrace{P_f}_{\text{潜力系数}} $$ ### 4. 平衡系数动态调整 根据牌局阶段调整攻防策略: $$ \alpha_t = \alpha_0 - 0.2 \cdot \delta_t $$ $$ \beta_t = \beta_0 + 0.2 \cdot \delta_t $$ 其中 $\delta_t$ 是牌局阶段因子(0=早期,1=晚期) ## 性能优化建议 1. **缓存机制**:对于相同手牌状态,缓存计算结果 2. **概率表预计算**:提前计算常见牌型的胡牌概率 3. **并行计算**:各花色权重计算可并行执行 4. **增量更新**:手牌变化时只更新受影响的花色 ## 相关扩展问题 1. 如何将花色权重分析与其他决策模块(如单牌价值计算)集成? 可设计权重传递机制:$$ V_{\text{final}} = V_{\text{base}} \times W_f \times V_{\text{safe}} $$ 其中 $W_f$ 是牌 $f$ 所属花色的权重[^1] 2. 在估算胡牌概率时,如何更精确地考虑剩余牌分布? 可使用马尔可夫链模型跟踪各花色剩余牌数量:$$ P(\text{win}|H_f) = \sum_{k=0}^{4} P(\text{摸到}k\text{张牌}) \times P(\text{胡牌}|H_f+k) $$ 3. 如何根据对手行为动态调整安全系数? 可引入对手弃牌模式分析:$$ S_f = 1 - \frac{\sum_{i=1}^{3} \text{对手}i\text{弃牌中}f\text{的比例}}{3} $$ 4. 花色权重分析如何适应不同麻将变种规则? 可通过规则参数化实现:$$ W_f = \begin{cases} 0 & \text{缺一门规则} \\ \alpha \cdot \frac{|H_f|}{|H|} + \beta \cdot P_{\text{win}}^f & \text{标准规则} \\ \text{特殊计算} & \text{其他变种} \end{cases} $$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值