zoukankan      html  css  js  c++  java
  • 【JZOJ3771】【NOI2015模拟8.15】小 Z 的烦恼【高精度】【数论】

    题目大意:

    题目链接:https://jzoj.net/senior/#main/show/3771
    ZZ最近遇上了大麻烦,他的数学分析挂科了。于是他只好找数分老师求情。
    善良的数分老师答应不挂他,但是要求小ZZ帮助他一起解决一个难题问题是这样的,现在有
    nn个标号为 1n1sim n 的球和mm个盒子,每个球都可以放进且只能放进一个盒子里面,但是要满足如下的规则:

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

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

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


    思路:

    若第一个盒子放xx,那么接下来的盒子就分别放2x,22x...2m1x2x,2^2x...2^{m-1}x个球。
    那么若可以放置,就必须使2m1xn2^{m-1}xleq n,所以xn÷2m1xleq ndiv 2^{m-1}
    很明显,第一个格子放奇数个球是成立的。因为2x2x无法得到奇数。那么ansans就加上nleq n的所有奇数个数。
    那么还有一部分偶数也是可以放置在第一个格子的。所以只需继续让n÷2mndiv 2^m(注意不是2m12^{m-1}),再统计奇数个数。直到n=0n=0为止。
    需卡常。


    代码:

    /*#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;
    }
    
  • 相关阅读:
    bzoj1015星球大战(并查集+离线)
    bzoj1085骑士精神(搜索)
    bzoj1051受欢迎的牛(Tarjan)
    左偏树学习
    hdu1512 Monkey King(并查集,左偏堆)
    左偏树(模板)
    PAT (Basic Level) Practice (中文) 1079 延迟的回文数 (20分) (大数加法)
    PAT (Basic Level) Practice (中文) 1078 字符串压缩与解压 (20分) (字符转数字——栈存放)
    PAT (Basic Level) Practice (中文) 1077 互评成绩计算 (20分) (四舍五入保留整数)
    PAT (Basic Level) Practice (中文) 1076 Wifi密码 (15分)
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998389.html
Copyright © 2011-2022 走看看