• bzoj 3462: DZY Loves Math II


    3462: DZY Loves Math II

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 211  Solved: 103
    [Submit][Status][Discuss]

    Description

    Input

    第一行,两个正整数 S 和 q,q 表示询问数量。
    接下来 q 行,每行一个正整数 n。

    Output

    输出共 q 行,分别为每个询问的答案。

    Sample Input

    30 3
    9
    29
    1000000000000000000

    Sample Output

    0
    9
    450000036

    HINT

    感谢the Loser协助更正数据


    对于100%的数据,2<=S<=2*10^6,1<=n<=10^18,1<=q<=10^5

     
     
    神dp+组合数学题、
    首先如果S有一个质因子的次数>1的话就全输出0;
    如果n<∑zs[i]的话也是输出0。
     
    首先把n减去所有质因子的和,吧问题转化成每个质因子可以选任意个。
     
    然后我们可以发现每个质因子pi能表示的数可以写成 x*S+y*pi ,其中y*pi<S。
    这样的话我们就枚举一下所有质因子的x的和,这个的范围区间大小不会超过7,因为∑(y*pi) <S*num
     
    然后问题就分成了两个部分:
    1.∑xi  =  k,其中xi可以是任意自然数。
    2.∑yi*pi  =  n-k*S,其中0<=yi*pi<S。
     
    这样的话,第一问题就是一个可重组合问题,直接上组合数;
    第二个问题就是多重背包问题,也是直接上多重背包。
    最后把两个答案乘起来(两个互不干涉,乘法原理)
     
     
    /**************************************************************
        Problem: 3462
        User: JYYHH
        Language: C++
        Result: Accepted
        Time:5736 ms
        Memory:141916 kb
    ****************************************************************/
     
    #include<bits/stdc++.h>
    #define ll long long
    #define maxn 2000005
    using namespace std;
    const int ha=1000000007;
    ll n;
    int d[15],num=0,S,q,now;
    int inv[20],f[2][maxn*9];
    int zssum=0,ans;
     
    inline int add(int x,int y){
        x+=y;
        if(x>=ha) return x-ha;
        else return x;
    }
     
    inline void dp(){
        f[0][0]=1;
        now=0;
        int pre=now,tp=S*num-zssum;
         
        for(int i=1;i<=num;i++){
            now^=1;
             
    //      memset(f[now],0,sizeof(f[now]));
             
            for(int j=0;j<d[i];j++){
                int tot=0;
                for(int u=j;u<=tp;u+=d[i]){
                    tot=add(tot,f[pre][u]);
                    if(u-j>=S) tot=add(tot,ha-f[pre][u-S]);
                     
                    f[now][u]=tot;
                }
            }
             
            pre=now;
        }
    }
     
    inline int C(ll x,int y){
        int an=1;
        for(int i=1;i<=y;i++) an=an*((ll)(x-i+1)%ha)%ha*(ll)inv[i]%ha;
        return an;
    }
     
    int main(){
        inv[1]=1;
        for(int i=2;i<=8;i++) inv[i]=-inv[ha%i]*(ll)(ha/i)%ha+ha;
         
        scanf("%d%d",&S,&q);
         
        int U=S;
        for(int i=2;i*(ll)i<=U;i++) if(!(U%i)){
            d[++num]=i,U/=i,zssum+=i;
            if(!(U%i)){
                while(q--) puts("0");
                return 0;
            }
        }
        if(U!=1) d[++num]=U,zssum+=U;
         
        dp();
         
        while(q--){
            ans=0;
             
            scanf("%lld",&n);
             
            if(n<zssum){
                puts("0");
                continue;
            }
             
            n-=zssum;
             
            int tp=min((ll)num,n/S);
            ll tt=n/S,lef=n-tt*S;
            for(int i=0;i<=tp;i++) ans=add(ans,C(tt-i+num-1,num-1)*(ll)f[now][i*S+lef]%ha);
             
            printf("%d
    ",ans);
        }
         
        return 0;
    }
    

      

  • 相关阅读:
    vsync信号产生与分发
    推荐看过不错的博客及网站
    证明质数有无数个
    242 Valid Anagram
    169 Majority Element
    快速排序--quicksort
    插入排序
    选择排序
    冒泡排序
    指针函数 函数指针 回调函数
  • 原文地址:https://www.cnblogs.com/JYYHH/p/8460213.html
Copyright © 2020-2023  润新知