D题循环节题解:首先发现对于每个p[i],给出X后,怎么求最小周期T,即找到T满足对于序列 对任意j都有
,不难发现
然后题目中又有T必须是质数的幂次的限制,根据式子可以发现,如果设 那么x在p1...ps上的指数最多只有一个小于p[i]相应的指数
现在问题转化为了n个数p1...pn要找到一个x使得对任意1<=i<=n,p[i]和x最多只有一个质因子的指数p[i]大于x
然后我们发现 也就是最多只有7个不同的质数相乘≤10^6,又n<=16,也就是总共最多只有112个质因子,2^16=65536,那么就可以设dp[i][s]表示处理到第i个质因子,当前s状态的数已经有一个质因子的指数大于x的指数的最小的x是多少,但是我们发现x的上限非常大,有(10^6)^16=10^96那么大,所以我们就设dp[i][s]表示成log(x)的最小值,原本转移是乘法现在就是加法,这样上限就只有log(10^96)那么大了。
预处理转移ns[i][j]表示第i个质因子指数是j,对应ns[i][j]状态的数在第i个质因子上指数大于j,转移考虑枚举第i个质因子的指数j,因为预处理了ns[i][j]就可以直接转移了,时间复杂度
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define ll long long
using namespace std;
const int M=1000005;
const int N=115;
const int S=(1<<16)+5;
const int mod=998244353;
const double inf=1000000000000000.0;
const double eps=1e-6;
int n,sz,tot,cnt,ans;
double mn;
bool vis[M];
int pri[M],p[N],b[N],f[N][S],c[N][N],ns[N][20];
double dp[N][S];
vector<int> d[N],r[N];
void getprime(int n){
tot=0;
vis[1]=1;
for (int i=2;i<=n;i++){
if (!vis[i]) pri[++tot]=i;
for (int j=1;j<=tot;j++){
if (i*pri[j]>n) break;
vis[i*pri[j]]=true;
if (i%pri[j]==0) break;
}
}
}
void init(){
for (int i=1;i<=n;i++){
int now=p[i],t=0;
for (int j=1;j<=tot&&pri[j]<=now;j++) if (now%pri[j]==0){
d[i].push_back(pri[j]);
b[++cnt]=pri[j];
r[i].push_back(0);
while (now%pri[j]==0){
now/=pri[j];
r[i][t]++;
}
t++;
}
}
sort(b+1,b+1+cnt);
cnt=unique(b+1,b+1+cnt)-b-1;
for (int i=1;i<=n;i++){
for (int j=0;j<d[i].size();j++){
int now=d[i][j];
now=lower_bound(b+1,b+1+cnt,now)-b;
c[i][now]=r[i][j];
}
}
for (int i=1;i<=cnt;i++){
int sum=1;
for (int j=0;j<=19;j++){
int s=0;
for (int k=1;k<=n;k++)
if (c[k][i]>j) s|=(1<<k-1);
ns[i][j]=s;
sum=sum*b[i];
if (sum>1000000) break;
}
}
}
int main(){
getprime(1000000);
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&p[i]);
sz=(1<<n)-1;
init();
memset(f,-1,sizeof(f));
f[0][0]=1;
for (int i=0;i<=cnt;i++)
for (int s=0;s<=sz;s++) dp[i][s]=inf;
dp[0][0]=0.0;
for (int i=0;i<cnt;i++){
for (int s=0;s<=sz;s++) if (f[i][s]!=-1){
int sum=1;
for (int j=0;j<=19;j++){
if ((ns[i+1][j]&s)==0){
int ss=s|ns[i+1][j];
if (dp[i][s]+log(sum)<dp[i+1][ss]){
dp[i+1][ss]=dp[i][s]+log(sum);
f[i+1][ss]=1ll*f[i][s]*sum%mod;
}
}
sum=sum*b[i+1];
if (sum>1000000) break;
}
}
}
ans=0; mn=inf;
for (int i=0;i<=sz;i++) if (dp[cnt][i]<mn){
mn=dp[cnt][i];
ans=f[cnt][i];
}
printf("%d\n",ans);
return 0;
}
京公网安备 11010502036488号