zoukankan      html  css  js  c++  java
  • Another Coin Weighing Puzzle North America Championship 2020

    Another Coin Weighing Puzzle North America Championship 2020

    题意

    有称(m)次天平的机会,现有一些盒子,每个盒子中有(k)个硬币

    某个盒子中有一个硬币比别的硬币都重,每次称天平可以得到天平的重量差

    问可以在(m)次内称出特殊硬币的最大盒子数

    [1 leq m,k leq 1e6 ]

    分析

    关键点是得出称量(m)次有效信息是重量差 (感觉也是这题最有思维量的地方),如果特殊硬币比普通硬币重(x),那么(m)次称量可能会得到的答案就是

    (-x:x:2x:3x...)

    显然,如果得到是(-2x:2x:4x:6x) 这样和上一个称量方法得到信息是重复的(无法确定x)

    所以其实就是求(m)次能得到的本质不同(即gcd = 1)的范围在([-k,k])序列比例

    这就是和前几天的CF类似的只需要莫比乌斯反演就可以得到的表达式乘上(mu[i])
    当然0要特殊考虑

    [ans = sum_{i=1}^k mu[i] (2lfloorfrac{k}{d} floor-1)^m + 1 ]

    代码

    特别注意!mu[i]可能是负数,所以运算要加个MOD

    #include<bits/stdc++.h>
    #define pii pair<ll,ll>
    #define fi first
    #define se second
    using namespace std;
    typedef long long ll;
    
    inline ll rd(){
    	ll x;
    	scanf("%lld",&x);
    	return x;
    }
    
    
    const int maxn = 2e6 + 5;
    const int MOD = 998244353;
    
    inline int mul(int a,int b){
    	return (ll)a * b % MOD;
    }
    
    inline void add(int &a,int b){
    	a += b;
    	if(a >= MOD) a -= MOD;
    }
    
    inline int ksm(int a,int b = MOD - 2,int m = MOD){
    	int ans = 1;
    	int base = a;
    	while(b){
    		if(b & 1) ans = mul(ans,base);
    		base = mul(base,base);
    		b >>= 1;
    	}
    	return ans;
    }
    
    int prime[maxn], prime_tot;
    int is_prime[maxn];
    int mu[maxn];
    
    void pre_calc(int lim) {
        mu[1] = 1;
        for (int i = 2; i <= lim; i++) {
            if (!is_prime[i]) {
                prime[++prime_tot] = i;
                mu[i] = -1;
            }
            for (int j = 1; j <= prime_tot; j++) {
                if (i * prime[j] > lim) break;
                is_prime[i * prime[j]] = 1;
                if (i % prime[j] == 0) {
                    mu[i * prime[j]] = 0;
                    break;
                }
                else mu[i * prime[j]] = -mu[i];
            }
        }
    }
    
    
    int main(){
    	pre_calc(maxn - 3);
    	int m = rd();
    	int k = rd();
    	int ans = 1;
    	for(int i = 1;i <= k;i++){
    		if(!mu[i]) continue;
    		int tmp = ksm(1 + k / i * 2,m);
    		tmp = MOD + tmp - 1;
    		tmp %= MOD;
    		ans += (MOD + (ll)mu[i] * tmp % MOD) % MOD;
    	   	ans %= MOD;	
    	}
    	printf("%d",ans);
    }
    
  • 相关阅读:
    HDU 3342 Legal or Not
    POJ 3723 Conscription
    HDU 1102 Constructing Roads
    题目1545:奇怪的连通图
    面向对象程序设计寒假作业2(实践题)
    面向对象程序设计寒假作业2(编程题1)
    面向对象程序设计寒假作业1
    面向对象程序设计寒假作业1(编程题)
    面向对象程序设计寒假作业1(实践题)
    面向对象程序设计寒假作业1(问答题)
  • 原文地址:https://www.cnblogs.com/hznumqf/p/15176538.html
Copyright © 2011-2022 走看看