[杂题] Codeforces Gym 101190 NEERC 16 L. List of Primes

关键是一个函数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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值