Codechef 12月 Kirito in labyrinth (分解质因数,素数筛改装)

Kirito in labyrinth 

Kirito faced a dangerous labyrinth, and now he requires your help.

He's in a tunnel which contains N different rooms. Each room contains Ai monsters inside it. He starts from room 1. Every time he stays near a room X, he may go in and clear it from monsters, or just leave the room locked and move to the room X+1. However, if he clears a room with K monsters, and the next room he clears consists of L monsters, then the greatest common divisor of K and L must be greater than 1, otherwise he will die (awful curse). Formally, let us say that the order of rooms he visited is i1i2, , ..., it. Then gcd(AijAij + 1> 1 for all j < t. Help him cross all the rooms by clearing the maximum number of rooms.

Input

The first line of input contains an integer T denoting the number of test cases.

The first line of each test case contains one integer N denoting the number elements in sequence.

The second line of each test case contains N integers where i-th integer is number of monsters in room Ai.

Output

For each test case, output the maximum number of rooms he could clear. (Kirito should survive.)

Constraints

  • 1 ≤ T ≤ 10
  • 1 ≤ N ≤ 105
  • 1 ≤ ai ≤ 107

Subtasks

  • Subtask 1: 1 ≤ N ≤ 103 - 30 points
  • Subtask 2: Original constraints - 70 points

Example

Input:
2
7
13 2 8 6 3 1 9
6
1 2 2 3 3 1
Output:
5
2

Explanation

Example 1. Kirito can clear the monsters in the rooms 2, 3, 4, 5, 7 in that order. These rooms consist of 2, 8, 6, 3, and 9 monsters, respectively. You can check that gcd(2, 8), gcd(8, 6), gcd(6, 3) and gcd(3, 9), all are greater than 1.

Example 2. Kirito can clear the monsters in the rooms numbered 2, 3. Each of these two rooms contains two monsters. And we know that gcd(2, 2) = 2 > 1.

There is one more possible solution: Kirito can clear the monsters in the rooms numbered 4, 5. These rooms contains 3 monsters each, and he can clear these rooms as gcd(3, 3) = 3 > 1.

这题的第一个反应是对每个数分解质因数,然后从左往右扫。当扫到一个数,求出这个数所有质因数中出现次数最多的(求出现的次数),然后把这个数的每个质因数的出现次数改为上述最大次数加一。模拟到最后。最后所有质因数中,出现次数最多的就是答案。

但是这样过不了task2,超时,原因是对每个数分解质因数时间有点长。

所以优化,我们拿出求2到N的素数筛模板。(我用的是红皮书)改一下。valid数组改为,valid[i]是i的一个质因数,如果这个数是质数,valid[i]=i;这样会快一点。因为

while(x!=1)
			{
				v[i].push_back(valid[x]);
				int t=valid[x];
				if(x%t==0)
				{
					x=x/t;
				}
				max_=max(max_,counter[t]);
			}

x是输入的一个数,v[i]是一个vector,保存的是第i个数(即x)的质因数,我们就不用先把一个数所有的质因数都求出来。通过valid[i],并且定义max_为这个数(x)中所有的质因数中,出现次数最多的次数。(counter[t]为t出现的次数)。最后注意加上counter[1]=1;

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
#define N 10000005
int valid[N];
int counter[N];
vector<int> v[N];
int main() 
{
	for(int i=2;i<N;i++)
	{
		valid[i]=0;
	}
	for(int i=2;i<=N;i++) if(valid[i]==0){
		if(N/i<i) break;
		for(int j=i*i;j<=N;j+=i) valid[j]=i;
	}
	for(int i=2;i<=N;i++)
	{
		if(valid[i]==0)
		{
			valid[i]=i;
		}
	}
	int cas;
	scanf("%d",&cas);
	while(cas--)
	{
		for(int i=0;i<N;i++)
		{
			v[i].clear();
		}
		memset(counter,0,sizeof(counter));
		int n;
		scanf("%d",&n);
		int x;
		for(int i=0;i<n;i++)
		{
			int max_=-1;
			scanf("%d",&x);
			if(x==1)
				continue;
			//cout<<valid[x]<<'x'<<endl;
			while(x!=1)
			{
				v[i].push_back(valid[x]);
				int t=valid[x];
				if(x%t==0)
				{
					x=x/t;
				}
				max_=max(max_,counter[t]);
			}
			//cout<<max_+1<<endl;
			for( int j=0;j<v[i].size();j++)
			{
				counter[v[i][j]]=max_+1;
			}
		}
		int mm=-1;
		counter[1]=1;
		for(int i=0;i<N;i++)
		{
			if(counter[i]>mm)
				mm=counter[i];
		}
		cout<<mm<<endl;
	}
	//system("pause");
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值