关键是一个函数Solve(int x,int *pre,int sum,int L)
表示已经考虑完了前x个质数 得到前缀pre 剩下需要的和为sum 下标从L开始
然后需要预处理下不用前x个质数 组成sum 的方案数和总长
然后超出范围的时候不处理
就能过了
#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=7700;
int pri[maxn+5],num;
int vst[maxn+5];
int m=0,n;
ll f[1005][10005],g[1005][10005];
inline int len(int x){
int ret=0;
while (x) ret++,x=x/10;
return ret+2;
}
inline void Pre(){
for (int i=2;i<=maxn;i++){
if (!vst[i]) pri[++num]=i;
for (int j=1;j<=num && pri[j]*i<=maxn;j++){
vst[i*pri[j]]=1; if (i%pri[j]==0) break;
}
}
n=num; m=0;
for (int i=1;i<=60;i++) m+=pri[i];
f[n+1][0]=0; g[n+1][0]=1;
for (int i=n;i;i--)
for (int j=0;j<=m;j++){
f[i][j]=f[i+1][j],g[i][j]=g[i+1][j];
if (j>=pri[i]){
f[i][j]+=f[i+1][j-pri[i]]+g[i+1][j-pri[i]]*len(pri[i]);
g[i][j]+=g[i+1][j-pri[i]];
}
}
}
int first=0; ll start=0;
char cur[100005]; int pnt=0;
inline void push(int x){
static char tmp[15],len;
len=0;
while (x) tmp[++len]=x%10+'0',x/=10;
for (int i=len;i;i--) cur[++pnt]=tmp[i];
cur[++pnt]=','; cur[++pnt]=' ';
}
ll L,R;
char ans[1000005]; int p;
inline void Solve(int x,int sum,ll sta){
if (sta>R) return;
if (sta+f[x+1][sum]+g[x+1][sum]*(2+pnt)<L) return;
if (!sum){
if (!first)
first=1,start=sta+1;
ans[++p]='[';
for (int i=1;i<=pnt-2;i++)
ans[++p]=cur[i];
ans[++p]=']'; ans[++p]=','; ans[++p]=' ';
if (start && start+p-1>=R){
for (ll i=L;i<=R;i++)
putchar(ans[i-start+1]);
exit(0);
}
return;
}
if (x==n) return;
if (f[x+1][sum]==0 || sum<pri[x+1]) return;
int tmp=pnt;
push(pri[x+1]);
Solve(x+1,sum-pri[x+1],sta);
sta+=f[x+2][sum-pri[x+1]]+g[x+2][sum-pri[x+1]]*(2+pnt);
pnt=tmp;
Solve(x+1,sum,sta);
}
int main(){
freopen("list.in","r",stdin);
freopen("list.out","w",stdout);
scanf("%I64d%I64d",&L,&R);
Pre();
ll t=0;
for (int i=2;;i++){
Solve(0,i,t);
t+=f[1][i]+g[1][i]*2;
}
return 0;
}