zoukankan      html  css  js  c++  java
  • 曹冲养猪

    【题目描述】
    自从曹冲搞定了大象以后,曹操就开始捉摸让儿子干些事业,于是派他到中原养猪场养猪,可是曹冲满不高兴,于是在工作中马马虎虎,有一次曹操想知道母猪的数量,于是曹冲想狠狠耍曹操一把。举个例子,假如有16 头母猪,如果建了3 个猪圈,剩下1 头猪就没有地方安家了。如果建造了5 个猪圈,但是仍然有1 头猪没有地方去,然后如果建造了7 个猪圈,还有2 头没有地方去。你作为曹总的私人秘书理所当然要将准确的猪数报给曹总,你该怎么办?
    【输入】
    第一行包含一个整数n (n <= 10) – 建立猪圈的次数,解下来n 行,每行两个整数ai, bi( bi <= ai <= 1000), 表示建立了ai 个猪圈,有bi 头猪没有去处。你可以假定ai,aj 互质.
    【输出】
    输出包含一个正整数,即为曹冲至少养母猪的数目。
    样例输入
    33
    1
    5 1
    7 2
    样例输出
    16

    【分析】

    这明显就是一道中国剩余定理的板子题吗!

    然而我并不会中国剩余定理,为此现学了一下……

    所谓的中国剩余定理,通式就是这个

    解法呢,首先我们要构造一个 L[i], L[i] 满足 L[i] % i == 1 && L[i] % j == 0 (j != i)。(i 就是 上面通式中的 a)

    构造完这个 L[i] 后,ans =  (∑ L[i] * ai (i : 1 -> n) )/ (m₁ * m₂ * …… * mn)。为什么呢,这要慢慢解释。

    先具体说一下怎么求 L[i] .

    L[i] 需要满足两个条件,我认为其中第二个条件比较好办:只要预先将所有的m都乘起来(设为M),然后除以 i ,这样 M 满足 M% j == 0(j != i) && M % i != 0。此时L[i]已经完成一半了,记录一下为mul[i]。

    接下来要使 L[i] % i == 1。一种方法是求逆元。因为 L[i] ≡ 1 (mod i),我们可令 mul[i] * x ≡ 1 (mod i),那么 mul[i] 和 x 互为 mod i 下的逆元。设法求 x 即可。

    mul[i] * x ≡ 1 (mod i) 可变形为 mul[i] * x - i * y = 1,这样的话就可以用 exgcd 求 x 了。这样 L[i] 就彻底解决了。

    再看看 ans 的求法。

    首先对于 L[i] * ai ≡ ai (mod mi) ,而对于任意的 j (j <= n && j != i) L[i] * ai ≡ 0 (mod mj),所以

                   x = L[1] * a1 + L[2] * a2 + …… + L[n] * an = L[i] *ai + 0 + 0 + …… + 0 (mod mi) = ai (mod mi)。

    说明 x 是通式的一个解。

    另外,假设  和 都是通式的解,那么:
                  
                  M∣ - 
     
    这里面用到了这么一个定理: 若 c | a, b | a, 那么 lcm(b, c) | a
    而在这道题中,mi 互质,所以 (m1 * m2 * …… * mn) |  - ,即 M |  - 
     
    所以通式的任意两个解相差 M 的整数倍
    那么所有解的形式为
                  L[1] * a1 + L[2] * a2 + …… + L[n] * an + k * M 
    所以最小整数解就是 mod M 下的解。
     
     
    上代码
     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<algorithm>
     6 using namespace std;
     7 typedef long long ll;
     8 const int maxn = 15;
     9 int n;
    10 ll L[maxn], b[maxn], p[maxn], multi[maxn], M = 1;
    11 ll d = 1, x, y;
    12 ll ans = 0;
    13 ll exgcd(ll a, ll b, ll& d, ll& x, ll& y)
    14 {
    15     if(!b) {d = a; x = 1; y = 0;}
    16     else {exgcd(b, a % b, d, y, x); y -= x * (a / b);}
    17 }
    18 int main()
    19 {
    20     scanf("%d", &n);
    21     for(int i = 1; i <= n; ++i)
    22     {
    23         scanf("%lld%lld", &p[i], &b[i]);
    24         M *= p[i];
    25     }
    26     for(int i = 1; i <= n; ++i)
    27     {
    28          multi[i] = M / p[i];
    29         exgcd(multi[i], p[i], d, x, y);
    30         x = (x + p[i]) % p[i];
    31         L[i] = multi[i] * x;
    32         ans += (L[i] * b[i]); 
    33     }
    34     ans %= M;
    35     printf("%lld
    ", ans);
    36 }
  • 相关阅读:
    iOS开发拓展篇—音频处理(音乐播放器1)
    iOS开发拓展篇—CoreLocation地理编码
    iOS开发拓展篇—CoreLocation定位服务
    iOS开发拓展篇—CoreLocation简单介绍
    iOS开发拓展篇—封装音频文件播放工具类
    图标框架Font Awesome
    WordPress基础:设置后台语言
    使用帝国备份王备份还原网站数据
    WordPress主题开发:加载脚本和样式
    WordPress主题开发:get_term_by和get_term_link
  • 原文地址:https://www.cnblogs.com/mrclr/p/8496952.html
Copyright © 2011-2022 走看看