[BZOJ3462]DZY Loves Math II

Posted ZLTJohn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ3462]DZY Loves Math II相关的知识,希望对你有一定的参考价值。

题目描述


2<=S<=2*10^6,1<=n<=10^18,1<=q<=10^5

解题思路

观察可得S的质因子的次幂不超过1,而且不超过6个,设有k个。
这让人浮想联翩。
设质因子 pici p i 选 c i 个计入拆分。
那么 n=ipici n = ∑ i p i c i 。现在问题是n很大,我们不能直接做,而且有 105 10 5 组询问。
n很大,我们考虑一种合法方案,每个 ci c i 都不小,而p又是s的约数,我们尝试给 ci%=spi c i % = s p i ,我们模了之后一样的方案归为一类,那么对这类的方案我们再把许多的s分配给不同的 pi p i ,就可以还原出原来的方案,那么此时假设要分配x个s,那么我们乘上系数 Ck1x+k1 C x + k − 1 k − 1
我们现在只需要算出恰好要分配x个s的类的方案就可以算出总方案数了,注意到模了之后每个 ci c i 不超过 s/pi s / p i ,我们完全可以做一个有个数限制的背包,做出当 i=1..kpici=y ∑ i = 1.. k p i c i = y 的每个y的方案数,回答的时候就可以直接弄了,一次询问是O(k)的,不过内存访问似乎不太连续…
注意到一个质因子至少被选一次,那么我们可以先让n减掉每个质因子,这样就不用考虑选没选了。

代码

#include<cstdio> 
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
//开 O2!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
using namespace std;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
#define cmax(a,b) (a=(a>b)?a:b)
#define cmin(a,b) (a=(a<b)?a:b)
typedef long long ll;
typedef long long LL;
typedef double db;
const int N=2000+5,mo=1e9+7,M=2e7+5;
int i,S,term,j,d[N],td,rev[N],q,k;
int f[M],g[M],h[1000005];
ll ans,rem,di,n;
void predo(int S)

    j=S;
    fo(i,2,S)
    if (S%i==0)
    
        d[++td]=i;
        S/=i;
        if (S%i==0) 
        
            term=1;
            return ;
        
    
    if (S>1) d[++td]=S;
    S=j;
    f[0]=1;
    fo(i,1,td)
    
        fo(j,0,S*i) g[j]=f[j];
        fo(j,0,S*i)
        
            k=j%d[i];
            h[k]=(h[k]+g[j]-((j-S>=0)?g[j-S]:0))%mo;
            if (h[k]<0) h[k]+=mo;
            f[j]=h[k];
        
    

int ksm(int x,int y)

    int ret=1;
    while (y)
    
        if (y&1) ret=1ll*ret*x%mo;
        y>>=1;
        x=1ll*x*x%mo;
    
    return ret;

ll c(ll m,ll n)

    ll i,ret=1;
    fd(i,m,m-n+1) ret=ret*(i%mo)%mo;
    fo(i,1,n) ret=ret*rev[i]%mo;
    return ret;

int main()

    freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    scanf("%d %d",&S,&q);
    predo(S);
    fo(i,1,10) rev[i]=ksm(i,mo-2);
    fo(i,1,q)
    
        ans=0;
        scanf("%lld",&n);
        fo(j,1,td) n-=d[j];
        if (term||n<0)
        
            printf("0\\n");
            continue;
        
        fo(j,0,td)
        
            rem=n%S+j*S;
            di=n/S-j;
            if (di<0) break;
            ans=(ans+f[rem]*c(di+td-1,td-1))%mo;
        
        printf("%lld\\n",ans);
    

以上是关于[BZOJ3462]DZY Loves Math II的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3309: DZY Loves Math

bzoj3561DZY Loves Math VI

[BZOJ3309]DZY Loves Math

Bzoj3481 DZY Loves Math III

Bzoj3309 DZY Loves Math

BZOJ3309DZY Loves Math