math(2018.10.27)

20%的数据直接暴搜就行,接下来我们考虑哪些数不能够出现在同一个集合中,就连一 条边,我们会发现前𝑛个数被我们分成了若干条链,每条链上实际只有两种选法。
于是我们就可以考虑最暴力的\(𝑑𝑝\)了,设\(𝑓(𝑖,𝑗)\)表示当前\(𝑑𝑝\)到第\(𝑖\)条链,一共选了\(𝑗\)个数的方案。如果当前链长为\(2𝑝\),则 \(𝑓(𝑖,𝑗) = 2𝑓(𝑖 −1,𝑗−𝑝)\),如果为\(2𝑝+1\),
\(𝑓(𝑖,𝑗)=𝑓(𝑖−1,𝑗−𝑝)+𝑓(𝑖−1,𝑗−𝑝 −1)\)。于是 50%的数据就可以通过了。
接下来考虑\(𝑗\)的下界。实际上对于\(2𝑝\)或者 \(2𝑝+1\) 的链,它选取的下界都是\(𝑝\)。理性感知一下,如果把所有的𝑗减去其下界再\(dp\),实际上方程就变成了\(𝑓(𝑖,𝑗) = 2𝑓(𝑖 −1,𝑗)\)或者\(𝑓(𝑖,𝑗) = 𝑓(𝑖 −1,𝑗)+𝑓(𝑖 −1,𝑗 −1)\)。于是答案就变成了某个组合数乘以 \(2\) 的幂次。我们再 考虑如何枚举链,链长最多为\(𝑂(𝑙𝑜𝑔𝑛)\),因此我们可以枚举链长,由于所有链开头都是奇数, 因此对于每个链长计算一下当前长度的链有多少条就行了,这个可以解一下不等式。
对于 80% 的数据直接预处理阶乘暴力计算组合数即可,100%的数据就用lucsa算一下组合数取模即可。
代码:

#include<cstdio>
#include<cmath>
using namespace std;
int inv[11000001],fac[11000001],mod=1e7+19;
long long mn,n,q,m,c,last;
int mi(int a,int b)
{
    int ans=1;
    while(b)
    {
        if(b&1)ans=1ll*ans*a%mod;
        b>>=1;a=1ll*a*a%mod;
    }
    return ans;
}
int lucas(long long x,long long y)
{
    if (x<y)return 0;
    if (x>=mod)return 1ll*lucas(x/mod,y/mod)*lucas(x%mod,y%mod)%mod;
    else return 1ll*fac[x]*inv[y]%mod*inv[x-y]%mod;
}
signed main()
{
    scanf("%lld%lld",&n,&q);fac[0]=1;
    for(int i=1;i<mod;i++)fac[i]=1ll*fac[i-1]*i%mod;
    inv[mod-1]=mi(fac[mod-1],mod-2);
    for(int i=mod-1;i>=1;i--)inv[i-1]=1ll*inv[i]*i%mod;
    for(int i=log2(n);i>=0;i--)
    {
        int x=n>>i,y=(x+1>>1)-(last+1>>1);mn+=y*(i+1>>1);
        if(i&1)c+=y;last=x;
    }
    c=mi(2,c);
    for(int i=1;i<=q;i++)
    {
        scanf("%lld",&m);
        if(m<mn)printf("0\n");
        else printf("%lld\n",1ll*lucas(n-2*mn,m-mn)*c%mod);
    }
}
posted @ 2018-10-28 17:09  蒟蒻--lichenxi  阅读(128)  评论(0编辑  收藏  举报