zoukankan      html  css  js  c++  java
  • bzoj3462: DZY Loves Math II

    状态很差脑子不清醒了,柿子一直在推错。。。。

    。。。

    不难发现这个题实际上是一个完全背包

    问题在于n太大了,相应的有质数的数量不会超过7个

    假设要求sigema(1~plen)i pi*ci=n 的方案数

    令xi=ci/(S*pi),yi=ci%(S/pi),注意yi<S/pi

    则等价于sigema(1~plen)i S*xi+yi*pi=n

    若令sigema(1~plen)i xi=m,则sigema(1~plen)yi*pi=n-m*S

    n-m*S=sigema(1~plen)yi*pi<plen*S,可推出n/S-plen<m<=n/S

    此时plen有用了,我们可以枚举m,那么对于x的方案用插板法得C(m+plen-1,plen-1),对于y直接背包plen*S,朴素的做法是O(plen*(plen*S)*S/pi)的,随便优化下就可以把S/pi去掉了,不过要稍微注意yi的限制。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    const int _=1e2;
    const int maxn=7*2*1e6+_;
    const LL mod=1e9+7;
    
    int plen,p[10];
    bool divi(int n)
    {
        plen=0;
        for(int i=2;i*i<=n;i++)
            if(n%i==0)
            {
                p[0]+=i;p[++plen]=i;n/=i;
                if(n%i==0)return false;
            }
        if(n!=1)p[0]+=n,p[++plen]=n;
        return true;
    }
    
    LL inv[10];
    void yu(){inv[1]=1;for(int i=2;i<=plen;i++)inv[i]=inv[mod%i]*(mod-mod/i)%mod;}
    LL C(LL n,LL m)
    {
        LL ret=1;
        for(int i=1;i<=m;i++)
        {
            ret=ret*(n%mod)%mod*inv[i]%mod; n--;
        }
        return ret;
    }
    LL f[2][maxn]; int now;
    void DP(int S)
    {
        int li=S*plen;
        now=0,f[now][0]=1;
        for(int i=1;i<=plen;i++)
        {
            now^=1;
            for(int j=0;j<li;j++)
            {
                f[now][j]=0;
                if(j-p[i]>=0)f[now][j]=(f[now][j]+f[now][j-p[i]])%mod;
                f[now][j]=(f[now][j]+f[now^1][j])%mod;
                if(j>=S/p[i]*p[i])f[now][j]=(f[now][j]-f[now^1][j-S/p[i]*p[i]]+mod)%mod;
            }
        }
    }
    
    int main()
    {
        freopen("3.in","r",stdin);
        freopen("a.out","w",stdout);
        int S,Q;
        scanf("%d%d",&S,&Q);
        if(!divi(S)){while(Q--)puts("0");return 0;}
        yu();DP(S);
        while(Q--)
        {
            LL n;
            scanf("%lld",&n);n-=p[0];
            if(n<0){puts("0");continue;}
            
            LL ans=0;
            for(LL m=max(0LL,n/S-plen+1);m<=n/S;m++)
            {
                ans=(ans+C(m+plen-1,plen-1)*f[now][n-m*S])%mod;
            }
            printf("%lld
    ",ans);
        }
        
        return 0;
    }
  • 相关阅读:
    LeetCode 55. 跳跃游戏(Jump Game)I II tag 数组 贪心 动态规划
    科学的意义
    umi前后端交互技术,通用型request配置
    TD demo在我们机器上
    Ubuntu挂载和登录服务器
    TD属性总结
    TD音乐界面添加keyboard的流程
    VS Code常用键
    TD打印 log方法
    TD自定义控件流程
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/10588412.html
Copyright © 2011-2022 走看看