首页 > 技术文章 > Another Coin Weighing Puzzle North America Championship 2020

hznumqf 2021-08-23 16:35 原文

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] (2\lfloor\frac{k}{d}\rfloor-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);
}

推荐阅读