zoukankan      html  css  js  c++  java
  • BZOJ 3462 DZY Loves Math II ——动态规划 组合数

    好题。

    首先发现$p$是互质的数。

    然后我们要求$sum_{i=1}^{k} pi*xi=n$的方案数。

    然后由于$p$不相同,可以而$S$比较小,都是$S$的质因数

    可以考虑围绕$S$进行动态规划。

    然后发现有时候许多情况是多余的。因为一整个$S$只能由一些相同的$p$组合而成。

    所以这些部分可以用组合数计算,剩下的部分可以用背包处理出来。

    需要滚动数组,而且需要前缀和转移。

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    #define int long long
    #define F(i,j,k) for (int i=j;i<=k;++i)
    #define D(i,j,k) for (int i=j;i>=k;--i)
    #define maxn 2000005
    #define md 1000000007
    int pri[10],f[2][maxn<<3],s,q,top=0;
    int Dp()
    {
        int now=0,pre=1;
        memset(f[now],0,sizeof f[now]);
        f[now][0]=1;
        F(i,1,top)
        {
            now^=1;pre^=1;memset(f[now],0,sizeof f[now]);
            int up=s/pri[i]-1;
            F(l,0,pri[i]-1)
            {
                int presum=0;
                for (int j=0;j<=(s*top-l)/pri[i];j++)
                {
                    presum+=f[pre][j*pri[i]+l];presum%=md;
                    if (j>=up+1) presum-=f[pre][(j-up-1)*pri[i]+l];
                    f[now][j*pri[i]+l]=presum;
                }
            }
        }
        return now;
    }
     
    int ksm(int a,int b)
    {
        int ret=1;
        for (;b;b>>=1,a=a*a%md) if (b&1) ret=ret*a%md;
        return ret;
    }
     
    int C(int n,int m)
    {
        n=n+1; m=m-1;
        n=n+m-1;
        int ret=1;
        for(int i=n;i>=n-m+1;i--)
            ret=ret*(i%md)%md;
        F(i,1,m) ret=ret*ksm(i,md-2)%md;
        return ret;
    }
     
    signed main()
    {
        scanf("%lld%lld",&s,&q);int x=s;
        F(i,2,sqrt(s))
        {
            if (s%i==0) s/=i,pri[++top]=i;
            if (s%i==0)
            {
                while(q--) printf("0
    ");
                return 0;
            }
        }
        if (s>1) pri[++top]=s; s=x;
        int now=Dp();
        while(q--)
        {
            int ret=0;
            int n;scanf("%lld",&n);
            F(i,1,top) n-=pri[i];
            if (n<0) {printf("0
    "); continue;}
            int m=n/s,k=n-m*s;
            F(i,0,min(top,m))
                ret=(ret+f[now][i*s+k]*C(top+m-i-top,top%md)%md)%md;
            printf("%lld
    ",(ret+md)%md);
        }
    }
    

      

  • 相关阅读:
    Python基础09 面向对象的进一步拓展
    Python快速教程 (手册)
    Python基础03 序列
    Python基础04 运算
    Python基础08 面向对象的基本概念
    Python基础07 函数
    Python基础10 反过头来看看
    Python基础05 缩进和选择
    Python进阶02 文本文件的输入输出
    Python进阶01 词典
  • 原文地址:https://www.cnblogs.com/SfailSth/p/6813535.html
Copyright © 2011-2022 走看看