【JZOJ3771】【NOI2015模拟8.15】小 Z 的烦恼【高精度】【数论】
题目大意:
题目链接:https://jzoj.net/senior/#main/show/3771
小最近遇上了大麻烦,他的数学分析挂科了。于是他只好找数分老师求情。
善良的数分老师答应不挂他,但是要求小帮助他一起解决一个难题问题是这样的,现在有
个标号为 的球和个盒子,每个球都可以放进且只能放进一个盒子里面,但是要满足如下的规则:
-
若把标号为 的球放进了第 个盒子,那么标号为 的球一定要在第 个盒子里面(若 )
-
若把标号为 的球放进了第 个盒子,并且 ,那么标号为 的球一定要在第 个盒子里面(若 )
小 的数分老师想要知道,给定了 和 的时候,第一个盒子最多能放进去多少个球。事实上,他已经推算出了公式,但是需要检验当 趋向于无穷大时是否仍然满足这个公式,因此 可能会非常大。
思路:
若第一个盒子放,那么接下来的盒子就分别放个球。
那么若可以放置,就必须使,所以。
很明显,第一个格子放奇数个球是成立的。因为无法得到奇数。那么就加上的所有奇数个数。
那么还有一部分偶数也是可以放置在第一个格子的。所以只需继续让(注意不是),再统计奇数个数。直到为止。
需卡常。
代码:
/*#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")*/
//以上卡常神器
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int MAXN=1120;
const int maxint=1000000000;
int T,len,k;
char ch[10010];
ll n[MAXN+1],ans[MAXN+1],m,t,s;
ll write(ll x)
{
if (x>9) write(x/10);
putchar(x%10+48);
}
bool check(ll a[]) //判断n是否为0
{
for (register int i=MAXN;i>=1;i--)
if (a[i]) return 0;
return 1;
}
ll cnt() //计算奇数个数
{
//不超过n的奇数个数就是[(n+1)/2],[]表示向下取整
ll a[MAXN+1];
memcpy(a,n,sizeof(a));
t=1;
for (register int i=MAXN;i>=len-3;i--) //len用来卡常
{ //n+1
if (!t) break;
a[i]+=t;
t=a[i]/maxint;
a[i]%=maxint;
if (i<len&&a[i]) len=i;
}
t=0;
for (register int i=len;i<=MAXN;i++) //除以2
{
a[i]+=t;
if (a[i]&1) t=maxint;
else t=0;
a[i]>>=1;
if (i==len&&!a[i]) len++;
}
t=0;
for (register int i=MAXN;i>=len-3;i--) //记录答案
{
ans[i]+=a[i]+t;
t=0;
while (ans[i]>=maxint)
{
t++;
ans[i]-=maxint;
}
if (i<len&&a[i]) len=i;
}
}
void div(ll a[],int x)
{
t=0;
for (register int i=len-3;i<=MAXN;i++)
{
t=t*maxint+a[i];
a[i]=t/x;
t%=x;
if (i==len&&!a[i]) len++;
}
}
int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%s",ch);
len=strlen(ch);
for (register int i=1;i<=len;i++)
n[MAXN-(len-i)/9]=n[MAXN-(len-i)/9]*10+ch[i-1]-48;
for (int i=1;i<=MAXN;i++) //人才卡常法
if (n[i])
{
len=i-1;
break;
}
scanf("%lld",&m);
div(n,1<<(m-1));
if (check(n))
{
putchar(48),putchar(10);
continue;
}
while (!check(n))
{
cnt();
div(n,(1<<m));
}
k=1;
while (!ans[k]) k++;
write(ans[k]);
ans[k]=0;
for (k++;k<=MAXN;k++)
{
if (ans[k]<10) putchar(48);
if (ans[k]<100) putchar(48);
if (ans[k]<1000) putchar(48);
if (ans[k]<10000) putchar(48);
if (ans[k]<100000) putchar(48);
if (ans[k]<1000000) putchar(48);
if (ans[k]<10000000) putchar(48);
if (ans[k]<100000000) putchar(48);
write(ans[k]);
ans[k]=0;
}
putchar(10);
}
return 0;
}