zoukankan      html  css  js  c++  java
  • 【题解】Another Coin Weighing Puzzle (构造)

    【题解】Another Coin Weighing Puzzle (构造)

    或许,这就是神仙题

    你有(n)包硬币,每包硬币里面都恰好有(k)个硬币。有一包硬币是假的,且假的硬币比真硬币重,且同种硬币重量相同(是个实数)。你可以使用天平称硬币,使用天平的条件是两边有数量相等的硬币。使用天平会返回两边重量之差,测量完之后硬币任你处置。你必须在第一次测量之前确定整个测量的行动策略(但是你可以通过观察每次的结果,把你预设的操作做完后回答假币是哪包),一包硬币中的(k)个硬币外观一样且和别的包的不一样(因此你可以辨认某个硬币是从哪包来的),在你最多使用天平(m)次的前提下,你最多可以在(n)等于多少包中,还能根据你的行动策略确定硬币中假的那一包。答案对(998244353)取模。

    硬币哥感觉这题很妙

    一包硬币的策略可以看做一个数列。设一个数列({a}) 代表那包假的硬币每一轮放了多少,这个数列长度为(m)且元素的值域为([-k,k]),正的值代表放天平右边,负的值代表放左边,0代表这轮不放

    设真硬币重量为(w),假硬币重量为(tw,t>1),第(i)轮的差值为(s_i)

    那么

    [(t-1)wa_i=s_i ]

    (t,w)是定值,我们可以知道:

    [{a_iover a_j}={s_jover s_i} ]

    (当(s_i=0, ext{then }a_i=0),若(s)全为0那么(a)全为0)

    (s)的具体大小对确定(a)是无意义的,这个值可以由(t,w)任意调节。

    但可以通过(s)可以得到(a)的比值,此外假若(a)数列所有非零元素的绝对值的(gcd> 1),这个策略和({{a_iover gcd}})是等价的,因此我们规定代表策略的数列的(gcd =1)

    显然,(t,w)不变的情况下,(s)数列和(gcd=1)的数列({a})一一对应。假设总共有(S)种不同的(s),那么我们弄(S)包硬币,且每包硬币分配一个不同的({a}),这样就可以根据(s)直接确定哪一包硬币是假的了,又根据抽屉原理不存在(n>S),而这个构造(n=S)。这么看来,(n=S= ext{count } s= ext{count } a)

    那么现在的问题就是( ext{count } a),经典莫比乌斯反演

    [ ext{ans}=sum_{i=1}^k mu(i)ig((1+lfloor{kover i} floor)^m-1ig) ]

    //@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;
    }
    
    
  • 相关阅读:
    Odoo权限设置机制
    Odoo10配置文件
    Odoo10——self的使用
    Odoo10 启动选项
    ubuntu安装nginx
    pycharm快捷键一览
    前端 -- HTML
    前端 -- CSS
    前端 -- JavaScript
    前端 -- BOM和DOM
  • 原文地址:https://www.cnblogs.com/winlere/p/12786802.html
Copyright © 2011-2022 走看看