1. 程式人生 > >[結論][高精度除法]JZOJ 3771 小Z的煩惱

[結論][高精度除法]JZOJ 3771 小Z的煩惱

b+ lose for img sam ide play click 學分

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("\n"); } }
View Code

[結論][高精度除法]JZOJ 3771 小Z的煩惱