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; }