Description
小 Z 最近遇上了大麻烦,他的数学分析挂科了。于是他只好找数分老师求情。
善良的数分老师答应不挂他,但是要求小 Z 帮助他一起解决一个难题问题是这样的,现在有 n 个标号为 1~n 的球和 m 个盒子,每个球都可以放进且只能放进一个盒子里面,但是要满足如下的规则:
-
若把标号为 i 的球放进了第 j 个盒子,那么标号为 2*i 的球一定要在第 j+1 个盒子里面(若 j<m)
-
若把标号为 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(modm),a≡1(mod2),a∗2x+m−1<=n)
所以我们考虑从0开始枚举x,先将n除去2m−1,每次统计1~n里面的奇数,然后将n除去2m即可,由于n很大,所以每次要高精度除法。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
char s[10050];
ll w,j;
int i,m;
struct gj
{
ll a[677];
int len;
void rd()
{
scanf("%s",s); int m=strlen(s);len=(m-1)/18+1;
for(int i=1; i<=len; i++)
for(ll j=m-i*18; j<m-(i-1)*18; j++)
if(j>=0) a[i]=a[i]*10+s[j]-'0';
while(len&&a[len]==0) len--;
}
void wr()
{
bool zw=false;
for(int i=len; i>=1; i--)
for(ll j=w/10; j>0; j/=10)
if(i<len) putchar(a[i]/j%10+'0');
else if(a[i]/j%10) putchar(a[i]/j%10+'0'),zw=true;
else if(zw) putchar(a[i]/j%10+'0');
if(!len) putchar('0');
}
gj operator / (const int &p)const
{
gj cll;
memset(cll.a,0,sizeof(cll.a));
cll.len=len;
ll psz=0,gh=w>>p,fdc=w&((1<<p)-1),xhr;
for(int i=len;i>=1;i--)
{
xhr=psz*gh+((a[i]+psz*fdc)>>p);
psz=(a[i]+psz*fdc)&((1<<p)-1);
cll.a[i]=xhr;
}
while(cll.len && cll.a[cll.len]==0) cll.len--;return cll;
}
gj operator + (const gj &p)const
{
gj cll;
memset(cll.a,0,sizeof(cll.a));
cll.len=max(len,p.len);
for(int i=1;i<=cll.len;i++) cll.a[i]=a[i]+p.a[i];
for(int i=1;i<=cll.len;i++) cll.a[i+1]+=cll.a[i]/w,cll.a[i]%=w;
if(cll.a[cll.len+1]) cll.len++;
return cll;
}
gj operator - (const gj &p){
gj cll;
memset(cll.a,0,sizeof(cll.a));
cll.len=len;
for(int i=1;i<=cll.len;i++) cll.a[i]=a[i]-p.a[i];
for(int i=1;i<=cll.len;i++) if(cll.a[i]<0) cll.a[i]+=w,cll.a[i+1]--;
while(cll.len && cll.a[cll.len]==0) cll.len--;
return cll;
}
}n,l,r,ans;
int main()
{
int t;
scanf("%d",&t);
w=1;
for(int i=1; i<=18; i++) w*=10;
while(t--)
{
memset(n.a,0,sizeof(n.a)); memset(ans.a,0,sizeof(ans.a)); ans.len=0;
n.rd();
scanf("%d",&m);
r=n/(m-1); l=n/m;
while(r.len)
{
ans=ans+r-l;
r=r/m; l=l/m;
}
ans.wr();
printf("\n");
}
}