其他分享
首页 > 其他分享> > 关于CodeForces Round #696(Div.2)B题心得

关于CodeForces Round #696(Div.2)B题心得

作者:互联网

2021-01-27 18:32:45

题目描述大致如下:

题目传送门

B. Different Divisors

time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output  

Positive integer x is called divisor of positive integer y, if y is divisible by x without remainder. For example, 1 is a divisor of 7 and 3 is not divisor of 8.

We gave you an integer dd and asked you to find the smallest positive integer a, such that

  • a has at least 4 divisors;
  • difference between any two divisors of aa is at least d.
Input

The first line contains a single integer t (1≤t≤3000) — the number of test cases.

The first line of each test case contains a single integer d(1≤d≤10000).

Output

For each test case print one integer a — the answer for this test case.

Example input
2
1
2
output
6
15
Note

In the first test case, integer 6 have following divisors: [1,2,3,6]. There are 4 of them and the difference between any two of them is at least 1. There is no smaller integer with at least 4 divisors.

In the second test case, integer 15 have following divisors: [1,3,5,15]. There are 4 of them and the difference between any two of them is at least 2.

The answer 12 is INVALID because divisors are [1,2,3,4,6,12]. And the difference between, for example, divisors 2 and 3 is less than d=2.

 于是,作为蒟蒻的我就开始了思考:(把待求的数设为k)
  1. 首先,这个除数可以为其自身和1.也就是说,其只需至少有两个其他的数被它整除。
  2. 我只需要遍历每一个数直到存在它可以有两个整除的数且[1,x,y,k]每两个数的差值均大于等于d。

这很容易实现,只需用一个小小的for循环。于是便有了我的第一个代码:

 

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
int arr[50010];
using namespace std;
int main()
{
	int t,d,j,num,ad,tip,k;//num为被整除数的数量
	cin >> t;
	for (int i=0; i < t; i++)
	{
		cin >> d;
		for (j = 6;; j++)
		{
			memset(arr, 0, sizeof(arr));
			num = 0;
			tip = 1;
			k = 1;
			while(k!=j+1)
			{
				if (j % k == 0)
				{
					arr[num] = k;
					num += 1;
				}
				k++;
			}
			if (num >= 4)
			{
				for (int l = 0; l < num - 1; l++)
				{
					if (arr[l + 1] - arr[l] < d)
					{
						tip = 0; break;
					}
				}
				if (tip == 0)
					continue;
				else
				{
					cout << j << endl;
					break;
				}
			}
 
		}
	}
}

 

  思路很好理解,从6开始一直向前寻找满足条件的最小k值,num为每一个k对应的被除数的数量。如果被除数的数量小于4,就不需要考虑,大于等于4时再去考虑被除数是否满足条件。

 


 

然鹅,理想很美好,全是TLE。

    该算法所需时间过长,无法满足题目所要求的时间限制。于是我就想利用本蒟蒻的线性筛先行处理。考虑的因素有以下几点:

  1. 首先满足要求的k一定是合数,因此,我可以使用线性筛先行把合数筛取到一个数组中,这样或许可以减少一些时间。
  2. 蒟蒻线性筛使用不熟练想练习一下。

然后就有了下面的代码:

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define N  50010;//0~N
int arr[N];
bool prime[N];//若为质数值为1,否则为0
int num[N],dnum[N];//num存质数,dnum存合数
using namespace std;
int main()
{
    int count = 0, dcount = 0;//用来存以判断的质数和合数的个数
    memset(prime, 1, sizeof(prime));
    for (int i = 2; i < N; i++)
    {
        if (prime[i] == 1)
        {
            num[count++] = i;
        }
        else { dnum[dcount++] = i; }
        for (int j = 0; j < count && num[j] * i <= N; j++)
        {
            prime[num[j] * i] = 0;
            if (i % num[j] == 0)//直到num[j]为i的最小质因数
            {
                break;
            }
        }
    }
	int t,d,j,num,ad = 0,tip,k;
	cin >> t;
	for (int i=0; i < t; i++)
	{
		cin >> d;
		for (j=1;; j++)
		{
			memset(arr, 0, sizeof(arr));
			num = 0;
			tip = 1;
			k = 1;
			while(k<= dnum[j] /2)
			{
				if (dnum[j] % k == 0)
				{
					arr[num] = k;
					num += 1;
				}
				k++;
			}
			if (num >= 3)
			{
				for (int l = 0; l < num - 1; l++)
				{
					if (arr[l + 1] - arr[l] < d)
					{
						tip = 0; break;
					}
				}
				if (tip == 0)
					continue;
				else
				{
					cout << dnum[j] << endl;
					break;
				}
			}

		}
	}
	return 0;
}

 

  但是,想都不用想, 代码仍然超时。

     这样子看是思路8太对了哇......

     我寻思:

  1.  任何一个合数都可以分解为至少两个质数的乘积。
  2. k一定为合数。
  3. 若要使k最小,就需要使k只为两个质因数的乘积。

    这么说我只需要找到这两个质数就可以啦......(狂喜)

码来!

 

#include<cstdio>
#include<cstring>
const int N = 50010;
bool prime[N];
int  num[N];
using namespace std;
int main()
{
    int cnt = 0;
    int t, k;
    scanf("%d", &t);
    memset(prime, 1, sizeof(prime));
    for (int i = 2; i <= N; i++)
    {
        if (prime[i] == 0)  num[cnt++] = i;
        for (int j = 0; j < cnt && num[j] * i <= N; j++)
        {
            prime[num[j] * i] = 1;
            if (i % num[j] == 0) break;
        }
    }
    while (t--)
    {
        int d;
        scanf("%d", &d);
        int a, b;
        for (int i = 0; i < cnt; i++)
        {
            if (num[i] - 1 >= d)
            {
                a = num[i];
                k = i;
                break;
            }
        }
        for (int i = k + 1; i < cnt; i++)
        {
            if (num[i] - a >= d)
            {
                b = num[i];
                break;
            }
        }
        printf("%d\n", a * b);
    }
    return 0;
}

 

  最后,附上标准答案供dl参考(我是看不懂我菜)

 

#include <iostream>
#include <vector>
 
using namespace std;
 
void solve()
{
    int x;
    cin >> x;
    vector<int> p;
    for (int i = x + 1; ; i++)
    {
        int t = 1;
        for (int j = 2; j * j <= i; j++)
        {
            if (i % j == 0)
            {
                t = 0;
                break;
            }
        }
        if (t)
        {
            p.push_back(i);
            break;
        }
    }
    for (int i = p.back() + x; ; i++)
    {
        int t = 1;
        for (int j = 2; j * j <= i; j++)
        {
            if (i % j == 0)
            {
                t = 0;
                break;
            }
        }
        if (t)
        {
            p.push_back(i);
            break;
        }
    }
    cout << min(1ll * p[0] * p[1], 1ll * p[0] * p[0] * p[0]) << "\n";
}

 

  

 

 

 

 

标签:arr,696,int,CodeForces,++,num,Div.2,integer,include
来源: https://www.cnblogs.com/zzx6869/p/14336376.html