loj 572 Misaka Network 与求和 —— min_25筛

题目:https://loj.ac/problem/572

推式子:https://www.cnblogs.com/cjoieryl/p/10150718.html

又学习了一下杜教筛hh;

原来 unsigned int 的输出是 %u 啊;

注意各处还是要用 (ll),不要不小心都写成 (uint) 了;

然而递归版很慢...

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef unsigned int uint;
typedef long long ll;
int const xn=1e6+5;
int n,m,K,pri[xn],cnt,w[xn],sqr;
uint prk[xn],h[xn],G[xn];
bool vis[xn];
uint pw(uint a,int b){uint ret=1; for(;b;b>>=1,a=a*a)if(b&1)ret=ret*a; return ret;}
void init(int mx)
{
  for(int i=2;i<=mx;i++)
    {
      if(!vis[i])pri[++cnt]=i,prk[cnt]=pw(i,K);
      for(int j=1;j<=cnt&&(ll)i*pri[j]<=mx;j++)
    {
      vis[i*pri[j]]=1;
      if(i%pri[j]==0)break;
    }
    }
}
int Id(int x)
{
  if(x>sqr)return n/x;
  return m-x+1;
}
uint F(int x,int y)
{
  if(pri[y]>x)return 0;
  uint ret=0;
  for(int i=y;i<=cnt&&(ll)pri[i]*pri[i]<=x;i++)//ll
    for(ll p0=pri[i];p0*pri[i]<=x;p0*=pri[i])
      ret+=F(x/p0,i+1)+(uint)prk[i]*(h[Id(x/p0)]-i+1);
  return ret;
}
uint S(int x)
{
  if(G[Id(x)]!=-1)return G[Id(x)];
  uint ret=F(x,1)+h[Id(x)];
  for(int i=2,j;i<=x;i=j+1)j=x/(x/i),ret-=(j-i+1)*S(x/i);
  return G[Id(x)]=ret;
}
int main()
{
  scanf("%d%d",&n,&K); sqr=sqrt(n); init(sqr);
  for(int i=1,j;i<=n;i=j+1)
    {w[++m]=n/i; j=n/w[m]; h[m]=w[m]-1;}
  for(int j=1;j<=cnt;j++)
    for(int i=1;i<=m&&(ll)pri[j]*pri[j]<=w[i];i++)
      h[i]=h[i]-h[Id(w[i]/pri[j])]+j-1;//w[i]
  memset(G,-1,sizeof G);
  uint ans=0;
  for(int T=1,nxt;T<=n;T=nxt+1)
    {
      nxt=n/(n/T);
      ans+=(uint)(n/T)*(n/T)*(S(nxt)-S(T-1));
    }
  printf("%u\n",ans);//
  return 0;
}
递归版

于是写成了循环版,真的变快了^_^

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef unsigned int uint;
typedef long long ll;
int const xn=1e6+5;
int n,m,K,pri[xn],cnt,w[xn],sqr;
uint prk[xn],h[xn],G[xn],f[xn];
bool vis[xn];
uint pw(uint a,int b){uint ret=1; for(;b;b>>=1,a=a*a)if(b&1)ret=ret*a; return ret;}
void init(int mx)
{
  for(int i=2;i<=mx;i++)
    {
      if(!vis[i])pri[++cnt]=i,prk[cnt]=pw(i,K);
      for(int j=1;j<=cnt&&(ll)i*pri[j]<=mx;j++)
    {
      vis[i*pri[j]]=1;
      if(i%pri[j]==0)break;
    }
    }
}
int Id(int x)
{
  if(x>sqr)return n/x;
  return m-x+1;
}
void getf()
{
  for(int i=cnt;i;i--)
    for(int j=1;j<=m&&(ll)pri[i]*pri[i]<=w[j];j++)
      for(ll p0=pri[i];p0*pri[i]<=w[j];p0*=pri[i])
    f[j]+=f[Id(w[j]/p0)]+(uint)prk[i]*(h[Id(w[j]/p0)]-i+1);
}
uint S(int x)
{
  if(G[Id(x)]!=-1)return G[Id(x)];
  uint ret=f[Id(x)]+h[Id(x)];
  for(int i=2,j;i<=x;i=j+1)j=x/(x/i),ret-=(j-i+1)*S(x/i);
  return G[Id(x)]=ret;
}
int main()
{
  scanf("%d%d",&n,&K); sqr=sqrt(n); init(sqr);
  for(int i=1,j;i<=n;i=j+1)
    {w[++m]=n/i; j=n/w[m]; h[m]=w[m]-1;}
  for(int j=1;j<=cnt;j++)
    for(int i=1;i<=m&&(ll)pri[j]*pri[j]<=w[i];i++)
      h[i]=h[i]-h[Id(w[i]/pri[j])]+j-1;//w[i]
  memset(G,-1,sizeof G);
  uint ans=0; getf();
  for(int T=1,nxt;T<=n;T=nxt+1)
    {
      nxt=n/(n/T);
      ans+=(uint)(n/T)*(n/T)*(S(nxt)-S(T-1));
    }
  printf("%u\n",ans);//
  return 0;
}

 

posted @ 2019-01-17 20:56  Zinn  阅读(225)  评论(0编辑  收藏  举报