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"); } }
原文地址:https://www.cnblogs.com/mastervan/p/10292776.html