zoukankan      html  css  js  c++  java
  • hdu 6169

    题目:找出【L,R】内,所有n*k的和,n为1或者是大于等于k的质数;

    思路:遇到很多次二次筛的,再次遇到还是忘记了反向思维,在此,我们不去找符合的情况,而是去寻找不符合的情况,因为符合的情况太难找,不符合的就很好找了,用K以下的质数去筛就可以了,考虑到当k>320000的时候,k^2超出数据范围,所以,这种情况要么只有K自己,要么没有,那么考虑k<320000的情况,在此我们只需要找出相应的n即可,定义一个 dp[i][j]表示1~i 这 i个数被前j个素数筛过以后剩下的数的和。 

    则: 
    dp[i][j]=dp[i][j1]pri[j]dp[i/pri[j]][j1]

    解释:对于dp[i][j],只需要考虑在dp[i][j1]的基础上减去第j个素数造成的影响。 
    对于[1,i]中一个会被第j个素数pri[j]筛去的数来说,其可以表示成ppri[j] 
    其中p<=i/pri[j],因为其不会被j1个素数筛去,故dp[i/pri[j]][j1]中的每一个数,乘上pri[j]之后一定就是那个会被第j个素数筛去的数,故递推式即为所求。

    小范围时候记忆化以下,可以快200ms左右,不记忆化也可以过;注意计算中间爆LL那种情况即可,代码:

    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    const LL mod=1e9+7;
    const int maxn=4e5+10;
    LL prim[28000];
    LL dp[10001][101];
    bool p[maxn];
    LL l,r,k;
    int siever()
    {
        for(int i=0;i<300;i++)
            for(int k=(i<<1)+3,j=k*i+k+i;j<160010;j+=k)
                p[j]=1;
        int sp=1;
        for(int i=0;i<160010;i++)
            if(!p[i])prim[sp++]=(i<<1)+3;
        prim[0]=2;
        return sp;
    }
    bool isprim(LL num)
    {
        if(num==2)return true;
        if(!(num&1))return false;
        if(num<320000)
            if(!p[(num-3)>>1])return true;
            else              return false;
        for(int i=0;prim[i]<320010;i++)
            if(num%prim[i]==0)return false;
        return true;
    }
    
    LL f(LL i,int j)
    {
        if(i<=1)return i;
        if(j==-1)return (i+1)%mod*(i%mod)%mod*500000004%mod;
        while(prim[j]>i&&j)j--;
        if(i<10001&&j<101)
            if(dp[i][j]!=-1)return  dp[i][j];
            else    return dp[i][j]=f(i,j-1)-prim[j]*f(i/prim[j],j-1)%mod;
        return f(i,j-1)-prim[j]*f(i/prim[j],j-1)%mod;
    }
    
    
    
    
    int main()
    {
        //freopen("input.txt","r",stdin);
        //freopen("output.txt","w",stdout);
        int si=siever();
        memset(dp,-1,sizeof dp);
        int T,cas=0;scanf("%d",&T);
        while(T--)
        {
            scanf("%lld%lld%lld",&l,&r,&k);
            if(k>r || !isprim(k)){printf("Case #%d: 0
    ",++cas);continue;}
            if(k>320000)
                if(k>=l)printf("Case #%d: %lld
    ",++cas,k%mod);
                else    printf("Case #%d: 0
    ",++cas);
            else
            {
                int j=lower_bound(prim,prim+si,(int)k)-prim;
                LL ans=f(r/k,j-1)*k%mod-f((l-1)/k,j-1)*k%mod;
               printf("Case #%d: %lld
    ",++cas,(ans%mod+mod)%mod);
            }
        }
        return 0;
    }
  • 相关阅读:
    python活力练习Day 31
    携程笔试题3--2020-09-08
    双指针应用
    华为笔试题之排序去重
    java架构师学习路线-Mybatis一级缓存源码分析
    java架构师学习之spring boot对比spring mvc有什么区别
    spring Cloud 开发内存占用过高时java架构师该如何解决
    java高级架构师教程-使用Maven配置Spring
    java高级架构师教程-Spring Boot快速入门
    java高级架构师教程-使用Java编程引导JPA
  • 原文地址:https://www.cnblogs.com/MeowMeowMeow/p/7428811.html
Copyright © 2011-2022 走看看