【題解】Another Coin Weighing Puzzle (構造)
或許,這就是神仙題吧
你有\(n\)包硬幣,每包硬幣里面都恰好有\(k\)個硬幣。有一包硬幣是假的,且假的硬幣比真硬幣重,且同種硬幣重量相同(是個實數)。你可以使用天平稱硬幣,使用天平的條件是兩邊有數量相等的硬幣。使用天平會返回兩邊重量之差,測量完之后硬幣任你處置。你必須在第一次測量之前確定整個測量的行動策略(但是你可以通過觀察每次的結果,把你預設的操作做完后回答假幣是哪包),一包硬幣中的\(k\)個硬幣外觀一樣且和別的包的不一樣(因此你可以辨認某個硬幣是從哪包來的),在你最多使用天平\(m\)次的前提下,你最多可以在\(n\)等於多少包中,還能根據你的行動策略確定硬幣中假的那一包。答案對\(998244353\)取模。
硬幣哥感覺這題很妙
一包硬幣的策略可以看做一個數列。設一個數列\(\{a\}\) 代表那包假的硬幣每一輪放了多少,這個數列長度為\(m\)且元素的值域為\([-k,k]\),正的值代表放天平右邊,負的值代表放左邊,0代表這輪不放
設真硬幣重量為\(w\),假硬幣重量為\(tw,t>1\),第\(i\)輪的差值為\(s_i\)
那么
\(t,w\)是定值,我們可以知道:
(當\(s_i=0,\text{then }a_i=0\),若\(s\)全為0那么\(a\)全為0)
\(s\)的具體大小對確定\(a\)是無意義的,這個值可以由\(t,w\)任意調節。
但可以通過\(s\)可以得到\(a\)的比值,此外假若\(a\)數列所有非零元素的絕對值的\(\gcd> 1\),這個策略和\(\{{a_i\over \gcd}\}\)是等價的,因此我們規定代表策略的數列的\(\gcd =1\)。
顯然,\(t,w\)不變的情況下,\(s\)數列和\(\gcd=1\)的數列\(\{a\}\)一一對應。假設總共有\(S\)種不同的\(s\),那么我們弄\(S\)包硬幣,且每包硬幣分配一個不同的\(\{a\}\),這樣就可以根據\(s\)直接確定哪一包硬幣是假的了,又根據抽屜原理不存在\(n>S\),而這個構造\(n=S\)。這么看來,\(n=S=\text{count } s=\text{count } a\)
那么現在的問題就是\(\text{count } a\),經典莫比烏斯反演
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; typedef long long ll;
inline int qr(){
int ret=0,f=0,c=getchar();
while(!isdigit(c))f|=c==45,c=getchar();
while(isdigit(c)) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=1e6+5;
const int mod=998244353;
int mu[maxn],pr[maxn],cnt,usd[maxn];
void pre(const int&n){
mu[1]=1;
for(int t=2;t<=n;++t){
if(!usd[t]) mu[t]=mod-1,pr[++cnt]=t;
for(int i=1;i<=cnt;++i){
if(1ll*pr[i]*t>n) break;
usd[pr[i]*t]=1;
if(t%pr[i]) mu[pr[i]*t]=mod-mu[t];
else break;
}
}
}
int ksm(const int&ba,const int&p){
int ret=1;
for(int t=p,b=ba;t;t>>=1,b=1ll*b*b%mod)
if(t&1) ret=1ll*ret*b%mod;
return ret;
}
int main(){
pre(1e6);
int m=qr(),k=qr(),Doinb=1;
for(int t=1;t<=k;++t)
Doinb=(Doinb+1ll*mu[t]*(ksm(k/t*2+1,m)-1))%mod;
cout<<Doinb<<endl;
return 0;
}