这道题首先对于0个物品是一个常数项
此后每增加一个物品,dp[i]的最高次项便增加1
所以对于每一个dp值,最后都是可以用一个多项式表示的
考虑这个多项式什么时候构成一个循环
设所有物品的最小公倍数为lcm,则lcm就会形成一个循环
则dp函数的s也会在lcm时形成一个循环
因为lcm很小
那么我们可以考虑拉格朗日插值法来求出这个多项式
代码如下
#include<cstdio>
int l,r;
int dp[1000000],n,a[20],ans,lcm,maxa;
const int mod=1e9+7;
int fast(int x,int y)
{
int ans=1;
while(y)
{
if(y&1) ans=1ll*ans*x%mod;
x=1ll*x*x%mod;
y>>=1;
}
return ans;
}
int moc(int x)
{
if(x>=mod) return x-mod;
if(x<0) return x+mod;
return x;
}
int gcd(int x,int y)
{
if(!y) return x;
return gcd(y,x%y);
}
int solve(int x)
{
int ans=0;
int remain=x%lcm;
for(int i=remain,j=1;j<=n+1;j++,i+=lcm)
{
int now=1;
for(int k=remain,l=1;l<=n+1;l++,k+=lcm)
if(j!=l)
{
now=1ll*now*moc(i-k)%mod;
}
now=fast(now,mod-2);
for(int k=remain,l=1;l<=n+1;l++,k+=lcm)
if(j!=l)
{
now=1ll*now*moc(x-k)%mod;
}
ans=moc(ans+1ll*dp[i]*now%mod);
}//v=x,x[i]=i,y[i]=dp[i]
return ans;
}
int main()
{
freopen("gugu.in","r",stdin);
freopen("gugu.out","w",stdout);
scanf("%d",&n);
lcm=1;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),lcm=a[i]/gcd(a[i],lcm)*lcm;
scanf("%d%d",&l,&r);
maxa=lcm*(n+1);
dp[0]=1;
for(int j=1;j<=n;j++)
{
for(int i=a[j];i<=maxa;i++)
{
dp[i]=moc(dp[i]+dp[i-a[j]]);
}
}
for(int i=1;i<=maxa;i++)
dp[i]=moc(dp[i]+dp[i-1]);
printf("%d\n",moc(solve(r)-solve(l-1)));
}
/*
3 45 67 64
1 1000000000
*/