将 \(1\) 到 \(n\) 分成若干组数,要求每组数的和均为质数,在这个前提下让组数尽量少,若存在一种分配方式,输出每个数所在的组的编号,有多组解输出任意一组解,若不存在,输出 \(?1\)。
设 \(m\) 为 \(1\) 到 \(n\) 的和(等差数列求和),进行分类讨论:
- \(m\) 是质数,所有的数分同一组;
- \(m\) 是偶合数,根据哥德巴赫猜想的推论,一定能分解为两个质数相加,\(O(m)\) 找到哪个数要分进第 \(2\) 组即可;
- \(m\) 是奇合数,若 \(m-2\) 是质数,则可分为两组,否则减去 \(3\),转化为偶合数再分解。
做完上面 \(3\) 步,就知道 \(-1\) 纯属诈骗,根本不可能存在。
时间复杂度 \(O(m)\),但 \(m\) 是 \(n^2\) 量级。
做的时候不知道哥德巴赫猜想,直接 gg,打完暴力走人。
下面是 AC 代码:
#include<bits/stdc++.h>
int prime[10000000],a[6001];
bool vis[36000000];
int main(){
int n=36000000,m=0,k;
for(int i=2;i<=n;++i){
if(!vis[i]) prime[++m]=i;
for(int j=1,v;j<=m;++j){
if((v=i*prime[j])>n) break;
vis[v]=true;
if(!(i%prime[j])) break;
}
}
scanf("%d",&n),k=n*(n+1)>>1;
if(vis[k]){
bool flag=false;
if(k&1){
if(!vis[k-2]) a[2]=2,flag=true;
else a[3]=3,k-=3;
}
if(!flag) for(int i=3;i<=k;++i)
if(!vis[i]&&!vis[k-i]){
for(int j=n;j;--j)
if(i>=j) a[j]=2,i-=j;
break;
}
}
for(int i=1;i<=n;++i)
printf("%d ",std::max(a[i],1));
return 0;
}