2018深圳-Ultra Weak Goldbach‘s Conjecture-(数论+rabin)

60 篇文章 1 订阅
54 篇文章 2 订阅

L

题意:
刚开始说哥德巴赫猜想任意一个大于2的偶数都能被两个质数相加,然后又说大于5的奇数能被3个质数相加。现在问你任意大于11的数,是否能用6个质因数相加,如果不能输出impossible否则输出6个数字。

思考:
刚开始说的2个定理,我总感觉会用到…把2的和5的联合起来,实际上不是按这来做的。对于任意一个>11的要表示成6个数字,那为何我不先把其中4个给用掉呢,然后就变成2个数相加即可,也就是变成了哥德巴赫,但是剩余的数需要是偶数。很明显如果n是奇数那么先减去2 2 2 3,如果是偶数先减去2 2 2 2。剩下的就直接哥德巴赫就行了。对了,由于n很大,直接check会太慢,用了rabin快速判断素数。同时用了快速乘,快速幂里面的乘法也用快速乘。因为模数是1e9+7,如果两个1e9+5相乘,就炸longlong了,所以快速成能保证不炸。为什么以前%1e9+7不会炸呢,因为long long最大可以存9e18,所以不会炸。这题同样是%1e9+7为啥炸了呢,因为rabin里面有个地方不是%1e9+7而是%x,所以有可能炸。

代码:

int T,n,m,k;
int va[M];
int pri[M],st[M],cnt;

int ksc(int a,int b,int p)
{
//	int sum = 0;
//	while(b)
//	{
//		if(b&1) sum = (sum+a)%p;
//		a = (a+a)%p;
//		b >>= 1;
//	}	
//	return sum;
	return (a*b-(int)(a/(long double)p*b+1e-3)*p+p)%p;
}

int ksm(int a,int b,int p)
{
	int sum = 1;
	while(b)
	{
		if(b&1) sum = ksc(sum,a,p);
		a = ksc(a,a,p);
		b >>= 1;
	}
	return sum;
}

bool rabin(int x)
{
	if(x==2) return true;
	if(x<2||!(x&1)) return false;
	int a = 0,b = x-1;
	while(!(b&1)) a++,b>>=1;
	srand(time(NULL));
	for(int i=1;i<=5;i++)
	{
		int t = rand()%(x-2)+2;
		int now = ksm(t,b,x),pre = now;
		for(int j=1;j<=a;j++)
		{
			now = ksc(now,now,x);
			if(now==1&&pre!=1&&pre!=x-1) return false;
			pre = now;
		}
		if(now!=1) return false;
	}
	return true;
}

void init(int x)
{
	st[1] = 1;
	for(int i=2;i<=x;i++)
	{
		if(!st[i]) pri[++cnt] = i;
		for(int j=1;pri[j]*i<=x;j++)
		{
			st[pri[j]*i] = 1;
			if(i%pri[j]==0) break;
		}
	}
}

/*
当然也可以直接check一遍
bool check(int x)
{
	int a = x,b = n-x;
	for(int i=1;i<=cnt&&pri[i]<=b;i++)
	{
		if(pri[i]==b) return true;
		if(b%pri[i]==0) return false;
	}
	return true; //这里为什么一定是true呢,因为一个大数,如果不是质数,他的因子一定在sqrt(x)之内,现在1e6之内都没有这个因子,所以他肯定是质数。当然了x最大是1e12,所以就看看1e6之内有没有就行了。
}
*/

signed main()
{
	IOS;
	init(1e6+5);
	cin>>T;
	for(int cs=1;cs<=T;cs++)
	{
		cin>>n;
		cout<<"Case "<<cs<<": ";
		if(n<=11)
		{
			cout<<"IMPOSSIBLE\n";
			continue;
		}
		if(n&1)
		{
			n -= 9;
			cout<<"2 2 2 3 ";
			for(int i=1;i<=cnt&&pri[i]<=n;i++)
			{
				if(rabin(n-pri[i]))
				{
					cout<<pri[i]<<" "<<n-pri[i]<<"\n";
					break;
				}
			}
		}
		else
		{
			n -= 8;
			cout<<"2 2 2 2 ";
			for(int i=1;i<=cnt&&pri[i]<=n;i++)
			{
				if(rabin(n-pri[i]))
				{
					cout<<pri[i]<<" "<<n-pri[i]<<"\n";
					break;
				}
			}
		}
	}
	return 0;
}

总结:
多多思考积累经验,把复杂的问题简单化,要多想想如何去转化成这样。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值