您的位置:首页 > 其它

BZOJ3462 DZY Loves Math II(动态规划+组合数学)

2018-09-22 15:22 381 查看

  容易发现这是一个有各种玄妙性质的完全背包计数。

  对于每个质数,将其选取个数写成ax+b的形式,其中x=S/pi,0<b<x。那么可以枚举b的部分提供了多少贡献,多重背包计算,a的部分直接组合数即可。多重背包计数可以前缀和优化。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 2000010
#define ll long long
#define P 1000000007
ll read()
{
ll x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
}
int S,m,prime
,f[N<<3],g[N<<3],inv[10],cnt=0;
int C(ll n,int m)
{
int s=1;
for (ll i=n;i>n-m;i--)
s=i%P*s%P;
return 1ll*s*inv[m]%P;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj3462.in","r",stdin);
freopen("bzoj3462.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
S=read(),m=read();
inv[1]=1;for (int i=2;i<=9;i++) inv[i]=P-1ll*(P/i)*inv[P%i]%P;
for (int i=2;i<=9;i++) inv[i]=1ll*inv[i]*inv[i-1]%P;
bool flag=1;
for (int i=2;i<=S;i++)
if (S%i==0)
{
prime[++cnt]=i;S/=i;
if (S%i==0) {flag=0;break;}
if (S==1) break;
}
for (int i=1;i<=cnt;i++) S*=prime[i];
f[0]=1;
for (int i=1;i<=cnt;i++)
{
g[0]=1;
for (int k=prime[i];k<=S*7;k++)
{
g[k]=(g[k-prime[i]]+f[k])%P;
f[k]=(g[k]-(k>=S?g[k-S]:0)+P)%P;
}
}
while (m--)
{
ll n=read();
if (!flag) printf("0\n");
else
{
for (int i=1;i<=cnt;i++) n-=prime[i];
if (n<0) printf("0\n");
else
{
int ans=0;
for (int i=0;i<=cnt;i++)
if (i*S<=n) ans=(ans+1ll*C(n/S-i+cnt-1,cnt-1)*f[n%S+i*S]%P)%P;
printf("%d\n",ans);
}
}
}
return 0;
}

 

 

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: