码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 2277 Poi2011 Strongbox 数论

时间:2015-03-03 20:43:06      阅读:275      评论:0      收藏:0      [点我收藏+]

标签:bzoj   bzoj2277   数论   

题目大意:给定n和k个整数,求mod n加法下的群G的一个子群G‘,满足a[1]~a[k-1]都不在群中而a[k]在群中


首先易证G‘一定是一个循环群

证明:显然若a在群中则a的逆元在群中

那么我们就有了减法运算

由群的封闭性可得若a和b都在群中则gcd(a,b)一定在群中

不妨设g为G‘中所有元素的gcd 那么群G‘‘={0,g,2g,...}一定是G‘的一个子群

由于G‘-G‘‘中的所有元素均不是g的倍数,故G‘∩(G‘-G‘‘)为空 G‘=G‘‘

由此可得G‘是以g为最小生成元的一个循环子群 大小为n/g


上面都是废话


总之我们现在就要找到一个数g,使得g|n且g|a[k],且对于任意1<=i<=k-1,g不是a[i]的约数

这个MS没有什么办法直接做


我们发现10^14以内的数约数个数最多只有17280个

因此我们将a[1]~a[k-1]中所有的数对n取gcd,排序去重,这样k的规模就减小到了17280

然后枚举gcd(n,a[k])的所有约数,暴力验证,取最小的g就是结果

时间复杂度O(√n+klogn+17280^2)

卡爆了


#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 250250
using namespace std;
int k,tot;
long long n,ans,a[M];
void Check(long long x)
{
	int i;
	for(i=1;i<=tot;i++)
		if(a[i]%x==0)
			return ;
	ans=min(ans,x);
}
int main()
{
	int i;
	cin>>n>>k;ans=n;
	for(i=1;i<=k;i++)
	{
		#ifdef ONLINE_JUDGE
			scanf("%lld",&a[i]);
		#else
			scanf("%I64d",&a[i]);
		#endif
		a[i]=__gcd(n,a[i]);
	}
	sort(a+1,a+k);
	for(i=1;i<k;i++)
		if(i==k+1||a[i]!=a[i+1])
			a[++tot]=a[i];
	for(i=1;(long long)i*i<=a[k];i++)
		if(a[k]%i==0)
		{
			Check(i);
			Check(a[k]/i);
		}
	cout<<n/ans<<endl;
	return 0;
}


BZOJ 2277 Poi2011 Strongbox 数论

标签:bzoj   bzoj2277   数论   

原文地址:http://blog.csdn.net/popoqqq/article/details/44042757

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!