zoukankan      html  css  js  c++  java
  • [结论][高精度除法]JZOJ 3771 小Z的烦恼

    Description

    小 Z 最近遇上了大麻烦,他的数学分析挂科了。于是他只好找数分老师求情。

    善良的数分老师答应不挂他,但是要求小 Z 帮助他一起解决一个难题问题是这样的,现在有 n 个标号为 1~n 的球和 m 个盒子,每个球都可以放进且只能放进一个盒子里面,但是要满足如下的规则:

    1.  若把标号为 i 的球放进了第 j 个盒子,那么标号为 2*i 的球一定要在第 j+1 个盒子里面(若 j<m)

    2.  若把标号为 i 的球放进了第 j 个盒子,并且 k*2=i,那么标号为 k 的球一定要在第 j-1 个盒子里面(若 j>1)

    小 Z 的数分老师想要知道,给定了 n 和 m 的时候,第一个盒子最多能放进去多少个球。事实上,他已经推算出了公式,但是需要检验当 n 趋向于无穷大时是否仍然满足这个公式,因此 n 可能会非常大。
     

    Input

    本题包含多组数据,第一行为一个数(T<=20),表示数据组数;以下 T 行,每组数据一行,包括两个数 n 和 m。

    Output

    每组数据输出一行,包括一个数,即第一个盒子最多能放进多少个球。
     

    Sample Input

    2
    10 2
    10 3

    Sample Output

    4
    1
     
     

    Data Constraint

    对于 10%的数据,n<=10^6

    对于 20%的数据,n<=10^9

    对于 30%的数据,m=2

    对于 100%的数据,n<=10^10000,2<=m<=25
     

    Hint

    样例解释:

    (1).{1,3,4,5}, {2,6,8,10}

    (2).{1},{2},{4}

    分析

    今日份最难

    经过一番推规律,我们可以得到如下结论

    放在第一个盒子里的数必定满足:

    a*2x(x≡0(mod m) a≡1(mod 2) a*2x+m-1≤n )

    那就很简单啦,我们只需要先给n除掉2m-1,然后统计n中的奇数个数,然后再除2m,再判断,重复即可

    因为n比较大所以需要高精度除法

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    const int N=1e3+10;
    const ll P=1e11;
    ll a[N],b[N];
    int T,m,lena,lenb;
    char s[N*10];
    
    void Div(ll x) {
        ll fm=0;
        for (int i=lena;i;i--)
            a[i]=fm*P+a[i],fm=a[i]%x,a[i]/=x;
        while (!a[lena]&&lena) lena--;
    }
    
    void Plus() {
        ll fm=0;
        for (int i=lena;i;i--)
            b[i]+=(fm*P+a[i])/2ll,fm=a[i]%2ll;
        lenb=max(lena-1,lenb);
        if (b[lenb+1]) lenb++;
        for (int i=1;i<=lenb;i++)
            b[i+1]+=b[i]/P,b[i]%=P;
        if (b[lenb+1]) lenb++;
    }
    
    int main() {
        for (scanf("%d",&T);T;T--) {
            memset(a,0,sizeof a);memset(b,0,sizeof b);
            scanf("%s%d",s+1,&m);int len=strlen(s+1);
            ll j=1;lena=1;lenb=0;
            for (int i=len;i;i--) {
                a[lena]+=(s[i]-'0')*j;j*=10ll;
                if (j==P) j=1,lena++;
            }
            Div(1ll<<m-1);
            do {
                j=a[1]%2;
                Plus();
                b[1]+=j;
                Div(1ll<<m);
            }
            while (lena);
            if (!lenb) lenb++;
            printf("%lld",b[lenb]);
            for (int i=lenb-1;i>0;i--) {
                j=P/10ll;
                while (b[i]<j&&j)
                    printf("0"),j/=10ll;
                printf("%lld",b[i]);
            }
            printf("
    ");
        }
    }
    View Code
    在日渐沉没的世界里,我发现了你。
  • 相关阅读:
    HDU1998奇数阶魔方 一个好玩的程序 按规则写蛮简单的
    ASCII码表
    排序之快速排序算法
    HDU1002 A + B Problem II
    SDUT2136数据结构实验之二叉树的建立与遍历
    (转)计算组合数整数拆分
    IE CSS Bug及解决方案参考手册
    包含空格的项目的文件/路径部分需要用括号括起来
    Ext学习笔记07 Window及Window中的布局
    Google Map 2.0 获取当前倍率和当前点击所在地理坐标
  • 原文地址:https://www.cnblogs.com/mastervan/p/10292776.html
Copyright © 2011-2022 走看看