题目传送门
题意:
给你 个数的序列,第 个数是 。
让你生成一个 个数的 序列。
序列的要求:
(1)字典序大于等于 序列。
(2)两两互质。即 。
题解:
通过素数筛的思路去解这道题。
从左往右生成 序列,构造 的方法如下:
序列的前 个数包括的质因子的倍数已经筛过了。
如果前 个数已经产生过大于对应位置的 序列的数,那么 不受 的限制。否则需满足 。
然后找到最小的合法的未被筛过的数即可。
注意路径压缩。
我写的递归的路径压缩会MLE,用非递归的路径压缩过的。
感受:
逐梦演艺圈!
一直MLE或TLE的感觉真是妙不可言。
这道题想了几分钟就会了。
然后开始MLE。我想1e6都开不了吗?
那我改成1e5总可以吧。
试了几发,可能是路径压缩递归的问题?
改成非递归,终于不MLE了。
开始TLE。
非递归写的有问题,这不是没有起到路径压缩的作用吗?
AC!
代码:
#include<bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int maxn = 3e6 + 5 ;
const int maxm = 1e6 + 5 ;
int n , a[maxm] ;
int cnt = 0 ;
bool vis[maxn] ;
int prime[maxm] ;
int nxt[maxn] ;
bool flag = 0 ;
void get_prime()
{
memset(vis , 0 , sizeof(vis)) ;
vis[1] = 1 ;
for(int i = 2 ; i <= maxn - 5 ; i ++)
{
if(!vis[i])
prime[++ cnt] = i ;
for(int j = 1 ; j <= cnt && i * prime[j] <= maxn - 5 ; j ++)
{
vis[i * prime[j]] = 1 ;
if(i % prime[j] == 0) break ;
}
}
}
int find(int u)
{
int temp = 0 ;
int y ;
for(int i = u ; ; i = nxt[i]) if(nxt[i] == i){temp = i ; break ;}
for(int i = u ; i <= temp ; i = y) y = nxt[i] , nxt[i] = temp + 1 ;
return temp ;
}
void cal(int x)
{
for(int i = x ; i <= maxn - 5 ; i += x)
if(nxt[i] == i) nxt[i] = i + 1 ;
}
void solve(int x , int id)
{
int y = find(x) ;
if(!flag && y > a[id]) flag = 1 ;
nxt[y] = y + 1 ;
printf("%d " , y) ;
for(int i = 1 ; i <= cnt && prime[i] * prime[i] <= y ; i ++)
{
if(y % prime[i] == 0)
{
cal(prime[i]) ;
while(y % prime[i] == 0) y /= prime[i] ;
}
}
if(y > 1) cal(y) ;
}
int main()
{
scanf("%d" , &n) ;
for(int i = 1 ; i <= n ; i ++) scanf("%d" , &a[i]) ;
get_prime() ;
for(int i = 1 ; i <= maxn - 5 ; i ++) nxt[i] = i ;
for(int i = 1 ; i <= n ; i ++)
if(!flag) solve(a[i] , i) ;
else solve(2 , i) ;
printf("\n") ;
return 0 ;
}