宿舍建群

37 阅读1分钟

假设两个人及以上便可创建一个QQ群,那么n个人的宿舍最多可能有几个不一样的QQ群呢?

输入

第一行有一个整数T,代表有T组数据。

下面T行每行是一个整数n,代表这个宿舍有n个人。

1<=T<=105

1<=n<=109

输出

对于每一个结果可能很大,所以你只需要输出对1000000007取模的结果

解题思路:

组合数Cn0+Cn1+Cn2+...+Cnn=2^n,证明可以用二进制数,0表示不取1表示取,其组合数共2^n种

程序代码:

#include<stdio.h>
#include<string.h>
const long long N=1000000007;
long long N1;
long long F(long long m,long long n);

int main()
{
	long long n,a,T,sum,p;
	scanf("%lld",&T);
	while(T--)
	{
		sum=1;
		a=2;
		scanf("%lld",&n);
		p=n;
		N1=n+1;
		while(p)
		{
			if(p%2==1)
				sum=F(sum,a);
			a=F(a,a);
			p/=2;
		}
		printf("%lld\n",(sum-n-1)%N);
	}
	return 0;
}
long long F(long long m,long long n)
{
	long long a[110],b[110],c[110],d[110];
	long long sum,t,i=0,j=0,k,p,q;
	while(m)
	{
		a[i++]=m%10;
		m/=10;
	}
	while(n)
	{
		b[j++]=n%10;
		n/=10;
	}
	memset(c,0,sizeof(c));
	for(p=0;p<i;p++)
		for(q=0;q<j;q++)
			c[p+q]+=a[p]*b[q];
	t=0;
	for(k=0;k<i+j-1;k++)
	{
		d[k]=(c[k]+t)%10;
		t=(c[k]+t)/10;
	}
	while(t)
	{
		d[k++]=t%10;
		t/=10;
	}
	sum=0;
	for(i=k-1;i>=0;i--)
	{
		sum=10*sum+d[i];
		if(sum%N>N1)
			sum=sum%N;
	}
	return sum;
}