您的位置:首页 > 其它

南邮 OJ 1404 取数游戏

2015-08-05 15:15 169 查看


取数游戏

时间限制(普通/Java) : 1000 MS/ 3000 MS 运行内存限制 : 65536 KByte

总提交 : 90 测试通过 : 23

比赛描述

lqp刚学了辗转相除法,正不亦乐乎。will 又出来捣乱,给lqp 留了个难题。

给 N 个数,用 a1,a2…an来表示。现在will 让lqp依次取数,第一个数可以随意取。假使目前取得 aj,下一个数取ak(k>j),则ak必须满足gcd(aj,ak)≥L。 到底要取多少个数呢?自然是越多越好!
不用多说,这不仅是给lqp的难题,也是给你的难题。

输入

第一行包含两个数N 和 L.

接下来一行,有 N 个数用空格隔开,依次是 a1,a2…an.

输出

仅包含一行一个数,表示按上述取法,最多可以取的数的个数。

样例输入

5 6

7 16 9 24 6

样例输出

3

提示

选取 3个数16、24、6。gcd(16,24)=8,gcd(24,6)=6。

2≤L≤ai≤1 000 000;

题目来源

JSOI2010

// AC 77MS
#include<iostream>
#define MAX_AI 1000001		//a[i]的最大值
#define MAX_N 50001			//数组A的最大长度,取1000的话会WA1
#define MAX_PRIME 1001		//处理的最大素数,可能会不够,不够的话再改吧
#define MAX_DIVISOR 1001	//约数最多个数
int N,L;
int a[MAX_N];
bool isPrime[MAX_PRIME];	//表示是否为素数
int primeNo;				//素数表的大小
int prime[MAX_PRIME];		//素数表
int primeFactorNo;			//某个a[i]的素因子表的大小
int primeFactor[MAX_N];		//某个a[i]的素因子表
int primeFactorN[MAX_N];	//某个a[i]每个素因子的幂
int divisorNo;				//某个a[i]的约数表的大小
int divisor[MAX_N];			//某个a[i]的约数表
char maxLen[MAX_AI];		//maxLen[k] 表示最后一个最大公约数为 k 的话,可以连成的最长队列是多少

void makePrimeTable(){
int i,j;
isPrime[2] = 1;
for(i=3;i<MAX_PRIME;i+=2){
isPrime[i] = 1;
}
for(i=3;i<MAX_PRIME;i+=2){
if(isPrime[i]){
for(j=(i<<1);j<MAX_PRIME;j+=i){
isPrime[j] = 0;
}
}
}
for(primeNo=0,i=2;i<MAX_PRIME;i++){
if(isPrime[i]){
prime[++primeNo] = i;
}
}
}

// 将 k 拆分成素因子乘积的形式,存放于primeFactor[] 和primeFactorN[]中
void split(int k){
int i;
primeFactorNo = 0;
for(i=1;i<primeNo && prime[i]<=k; i++){
if(0==k%prime[i]){
primeFactor[++primeFactorNo] = prime[i];
primeFactorN[primeFactorNo] = 0;
while(0==k%prime[i]){
primeFactorN[primeFactorNo]++;
k /= prime[i];
}
}
}
if(k!=1){
primeFactor[++primeFactorNo] = k;				//最后一个存的可能不是素数
primeFactorN[primeFactorNo] = 1;
}
}

void dfs(int index, int Number){
if(index>primeFactorNo){
divisor[++divisorNo] = Number;
return;
}
int i;
dfs(index+1,Number);
for(i=1;i<=primeFactorN[index];i++){
Number *= primeFactor[index];
dfs(index+1,Number);
}
}

// 利用 primeFactor[]数组和primeFactorN[primeFactorNo] 制作约数表
void makeDivisorTable(){
divisorNo = 0;
dfs(1,1);
}

int refleshMaxLen(){
int i,len=0;					//len记录用当前数字的约数作为最后一组公约数的最大长度
for(i=1;i<=divisorNo;i++){
if(divisor[i]>=L && maxLen[divisor[i]]>len){
len = maxLen[divisor[i]];
}
}
len++;							//有了当前分析的这个数字之后,长度增加一
for(i=1;i<=divisorNo;i++){
if(divisor[i]>=L){
maxLen[divisor[i]] = len;
}
}
return len;
}

int main(){
//	freopen("test.txt","r",stdin);
int i,j,maxLength=0;
makePrimeTable();
scanf("%d%d",&N,&L);
for(i=1;i<=N;i++){
scanf("%d",a+i);
}
for(i=1;i<=N;i++){
split(a[i]);
makeDivisorTable();
j = refleshMaxLen();
if(maxLength<j){
maxLength = j;
}
}
printf("%d\n",maxLength);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: