• Another Coin Weighing Puzzle(莫比乌斯反演,思维)


    题目

    source

    (n)包硬币,其中有一包硬币里全是假硬币。假硬币比真硬币略重,但是不知道真假硬币的确切重量。可以用天平称重(m)次,每次可以往天平两端任意分配硬币包内的硬币。当天平两端硬币数量相等时,就会显示左端重量减去右端重量的值(这个值可正可负数)。

    题解

    假设真硬盘重(s),假硬币重(s+x)

    假设假硬币在第(i)次称重放了(a_i)个,那么结果就是(a_i x)(a_i< 0)代表放左边,(a_i > 0)代表放右边。那么根据每次称重的结果序列({a_1x,a_2x,a_3x,...,a_mx})约分后可以得到({a_1,a_2,a_3,...,a_m})。可以知道约分后有(gcd(a_1,a_2,...,a_m)=1),这个不同序列和每个硬币包的放置策略是一一对应的,即答案就是满足下列条件的序列数量:

    • (-kle a_i le k)
    • (gcd(a_1,...,a_m)=1)({a_i})均为0。

    以样例2 1为例,满足条件的序列有:

    ( 0, 0)

    ( 0, 1)

    ( 0, -1)

    ( 1, 0)

    ( 1, 1)

    ( 1, -1)

    (-1, 0)

    (-1, 1)

    (-1, -1)

    共9种,第一次称重9个硬币包分配方案为({0,0,0,1,1,1,-1,-1,-1}),第二次称重分配方案为({0,1,-1,0,1,-1,0,1,-1})。根据天平返回结果序列约分后查表就可以知道那一包是假硬币。

    可以证明这个是最多的(鸽巢原理),而且是合法的(由于对称,每次称重两边放的硬币数一定是相等的)。

    使用莫比乌斯反演,容易得到

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

    #include <bits/stdc++.h>
    
    #define endl '
    '
    #define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
    #define mp make_pair
    #define seteps(N) fixed << setprecision(N) 
    typedef long long ll;
    
    using namespace std;
    /*-----------------------------------------------------------------*/
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    #define INF 0x3f3f3f3f
    
    const int N = 1e6 + 10;
    const int M = 998244353;
    const double eps = 1e-5;
    
    int isnp[N];
    int pri[N];
    int mu[N];
    int cnt;
    
    inline ll qpow(ll a, ll b, ll m) {
        ll res = 1;
        while(b) {
            if(b & 1) res = (res * a) % m;
            a = (a * a) % m;
            b = b >> 1;
        }
        return res;
    }
    
    int main() {
        IOS;
        isnp[1] = 1;
        mu[1] = 1;
        for(int i = 2; i < N; i++) {
            if(!isnp[i]) {
                mu[i] = -1;
                pri[cnt++] = i;
            }
            for(int j = 0; j < cnt && i * pri[j] < N; j++) {
                mu[i * pri[j]] = -mu[i];
                isnp[i * pri[j]] = 1;
                if(i % pri[j] == 0) {
                    mu[i * pri[j]] = 0;
                    break;
                }
            }
        }
        ll m, k;
        cin >> m >> k;
        ll ans = 0;
        for(int i= 1; i <= k; i++) {
            ans = (ans + (qpow(1 + 2 * (k / i), m, M) - 1 + M) * mu[i] % M + M) % M;
        }
        cout << (ans + 1 + M) % M << endl;
    }
    
  • 相关阅读:
    MVC基础
    JQuery基本知识、选择器、事件、DOM操作、动画
    LinQ各种方式查询、组合查询、IQueryable集合类型
    LinQ 创建连接、简单增删改查
    webform-AJAX
    JavaScricp(总回顾)
    响应式布局(收藏)
    webform:分页组合查询
    webform:图片水印、验证码制作
    【转】开发人员一定要加入收藏夹的网站
  • 原文地址:https://www.cnblogs.com/limil/p/15172239.html
Copyright © 2020-2023  润新知