关于CodeForces Round #696(Div.2)B题心得
2021-01-27 18:32:45
题目描述大致如下:
B. Different Divisors
time limit per test1 secondmemory limit per test256 megabytesinputstandard inputoutputstandard outputPositive 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.
InputThe 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).
OutputFor each test case print one integer a — the answer for this test case.
Exampleinput2 1 2output6 15NoteIn 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,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。
该算法所需时间过长,无法满足题目所要求的时间限制。于是我就想利用本蒟蒻的线性筛先行处理。考虑的因素有以下几点:
- 首先满足要求的k一定是合数,因此,我可以使用线性筛先行把合数筛取到一个数组中,这样或许可以减少一些时间。
- 本蒟蒻线性筛使用不熟练想练习一下。
然后就有了下面的代码:
#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太对了哇......
我寻思:
- 任何一个合数都可以分解为至少两个质数的乘积。
- k一定为合数。
- 若要使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";
}

浙公网安备 33010602011771号