zoukankan      html  css  js  c++  java
  • bzoj 3129

    非常好的一道数学题,考察了大量数论和组合数学的知识

    在做本题之前强烈建议先完成下列两个背景知识:

    ①:

    bzoj 2142礼物

    因为本题的一部分数据需要利用到拓展卢卡斯定理,而礼物是拓展卢卡斯定理的裸题,先做礼物是一个比较好的选择

    有困难戳这里https://blog.csdn.net/lleozhang/article/details/82884768

    ②:

    CF451E

    本题的核心思想和CF451E完全相同,CF451E稍简单一些,所以先理解这里的思想再做本题会发现难度降了不少

    有困难戳这里https://blog.csdn.net/lleozhang/article/details/83590652

    接下来的讨论在你掌握了上两个背景知识的基础上进行:

    首先我们注意到一点:他要求方程的解为正整数,那么这样不利于操作,所以我们把m减掉一个n,相当于预设每个x至少为1,然后仅需要求新方程的解非负即可

    不要忘记修改上下界

    那么这样就可以发现:前面1-n1的要求可以与CF451E完全一致,那么可以使用完全相同的方法来处理。

    至于下界的问题:我们可以实现预设所有解均满足下界,那么我们可以再将m减掉所有的下界,这样其他所有x都可以随便选了。

    这样就可以用于CF451E完全相同的方法解决掉这道题

    可是不要忘记:本题的模数很有特点:

    对于40%的数据,模数为10007,这是个质数,直接卢卡斯定理求组合数即可

    对于另30%的数据,模数为一个大合数,但是可以质因子分解成几个不同的质数的乘积,那么对每个质数跑卢卡斯,最后中国剩余定理合并即可

    对于最后30%的数据,模数为一个大合数,而且质因子分解之后有同一质数的幂次,所以只能使用拓展卢卡斯合并了

    // luogu-judger-enable-o2
     
    #include <cstdio>
    #define ll long long
    int T,p;
    int n,m,n1,n2;
    int aa[15];
    int bb[15];
    ll a[15];
    ll s[10];
    ll p0[4]={0,5,7,101};
    ll pu[4]={0,125,343,10201};
    ll num[4]={0,3,3,2};
    ll mode[5]={10007,2,3,11,397};
    ll inv[20005][5];
    ll mul[20005][5];
    struct node
    {
        ll mi;
        ll val;
    };
    void init()
    {
        for(int i=0;i<=4;i++)
        {
            inv[0][i]=inv[1][i]=1;
            mul[0][i]=mul[1][i]=1;
            for(int j=2;j<mode[i];j++)
            {
                inv[j][i]=(mode[i]-mode[i]/j)*inv[mode[i]%j][i]%mode[i];
            }
            for(int j=2;j<mode[i];j++)
            {
                mul[j][i]=mul[j-1][i]*j%mode[i];
                inv[j][i]=inv[j-1][i]*inv[j][i]%mode[i];
            }
        }
    }
    void ex_gcd(ll a,ll b,ll &x,ll &y)
    {
        if(b==0)
        {
            x=1;
            y=0;
            return;    
        }
        ex_gcd(b,a%b,x,y);
        ll t=x;
        x=y;
        y=t-(a/b)*x;
    }
    ll C(ll x,ll y,int num)
    {
        if(x<y)
        {
            return 0;
        }else if(x==y)
        {
            return 1;
        }
        if(x<mode[num])
        {
            return mul[x][num]*inv[y][num]%mode[num]*inv[x-y][num]%mode[num]; 
        }else
        {
            return C(x%mode[num],y%mode[num],num)*C(x/mode[num],y/mode[num],num)%mode[num];
        }
    }
    ll china()
    {
        ll M=262203414;
        ll ret=0;
        for(int i=1;i<=5;i++)
        {
            ll M0=M/mode[i-1];
            ll x,y;
            ex_gcd(M0,mode[i-1],x,y);
            x=(x%mode[i-1]+mode[i-1])%mode[i-1];
            ret+=x*a[i]%M*M0%M;
            ret%=M;
        }
        return ret;
    }
    ll solve(ll x,ll y)
    {
        for(int i=1;i<=5;i++)
        {
            a[i]=C(x,y,i-1);
        }
        return china();
    }
    ll pow_mul(ll x,ll y,ll mod)
    {
        ll ans=1;
        while(y)
        {
            if(y&1)
            {
                ans*=x;
                ans%=mod;
            }
            x*=x;
            x%=mod;
            y>>=1;
        }
        return ans;
    }
    ll get_inv(ll a,ll b)
    {
        ll x,y;
        ex_gcd(a,b,x,y);
        return (x%b+b)%b;
    }
    node get_mul(ll x,ll num)
    {
        if(x==0)
        {
            return (node){0,1};
        }
        ll ans=1;
        ll p1=x/p0[num],p2=x/pu[num];
        if(p2)
        {
            for(ll i=2;i<pu[num];i++)
            {
                if(i%p0[num])
                {
                    ans*=i;
                    ans%=pu[num];
                }
            }
            ans=pow_mul(ans,p2,pu[num]);
        }
        for(ll i=pu[num]*p2+1;i<=x;i++)
        {
            if(i%p0[num])
            {
                ans*=i;
                ans%=p;
            }
        }
        node re=get_mul(p1,num);
        return (node){re.mi+x,ans*re.val%p};
    }
    ll get_C(ll x,ll y,ll num)
    {
        if(x<y)
        {
            return 0;
        }else if(x==y)
        {
            return 1;
        }
        node f1=get_mul(x,num);
        node f2=get_mul(y,num);
        node f3=get_mul(x-y,num);
        ll t1=pow_mul(p0[num],f1.mi-f2.mi-f3.mi,pu[num])*f1.val%pu[num];
        ll t2=get_inv(f2.val,pu[num]);
        ll t3=get_inv(f3.val,pu[num]);
        return t1*t2*t3%pu[num];
    }
    ll china_again()
    {
        ll M=p;
        ll ret=0;
        for(int i=1;i<=3;i++)
        {
            ll M0=M/pu[i];
            ll x,y;
            ex_gcd(M0,pu[i],x,y);
            x=(x%pu[i]+pu[i])%pu[i];
            ret+=x*M0%M*a[i]%M;
            if(ret>=M)
            {
                ret-=M;
            }
        }
        return ret;
    }
    ll ex_lucas(ll x,ll y)
    {
        for(int i=1;i<=3;i++)
        {
            a[i]=get_C(x,y,i);
        }
        return china_again();
    }
    int main()
    {
        scanf("%d%d",&T,&p);
        init();
        while(T--)
        {
            scanf("%d%d%d%d",&n,&n1,&n2,&m);
            m-=n;
            for(int i=1;i<=n1;i++)
            {
                scanf("%d",&aa[i]);
                aa[i]--;
            }
            for(int i=1;i<=n2;i++)
            {
                scanf("%d",&bb[i]);
                bb[i]--;
                m-=bb[i];
            }
            if(m<0)
            {
                printf("0
    ");
                continue;
            }else if(m==0)
            {
                printf("1
    ");
                continue;
            }
            if(p==10007)
            {
                ll ans=0;
                for(int i=0;i<(1<<n1);i++)
                {
                    int t1=m;
                    int flag=1;
                    for(int j=0;j<n1;j++)
                    {
                        if((1<<j)&i)
                        {
                            t1-=(aa[j+1]+1);
                            flag=-flag;
                        }
                    }
                    if(t1<0)
                    {
                        continue;
                    }
                    ans+=flag*C(t1+n-1,n-1,0);
                    ans=(ans%p+p)%p;
                }
                printf("%lld
    ",ans);
            }else if(p==262203414)
            {
                ll ans=0;
                for(int i=0;i<(1<<n1);i++)
                {
                    int t1=m;
                    int flag=1;
                    for(int j=0;j<n1;j++)
                    {
                        if((1<<j)&i)
                        {
                            t1-=(aa[j+1]+1);
                            flag=-flag;
                        }
                    }
                    if(t1<0)
                    {
                        continue;
                    }
                    ans+=flag*solve(t1+n-1,n-1);
                    ans=(ans%p+p)%p;
                }
                printf("%lld
    ",ans);
            }else
            {
                ll ans=0;
                for(int i=0;i<(1<<n1);i++)
                {
                    int t1=m;
                    int flag=1;
                    for(int j=0;j<n1;j++)
                    {
                        if((1<<j)&i)
                        {
                            t1-=(aa[j+1]+1);
                            flag=-flag;
                        }
                    }
                    if(t1<0)
                    {
                        continue;
                    }
                    ans+=flag*ex_lucas(t1+n-1,n-1);
                    if(ans<0)
                    {
                        ans+=p;
                    }else if(ans>=p)
                    {
                        ans-=p;
                    }
                }
                printf("%lld
    ",ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    LeetCode Binary Tree Inorder Traversal
    LeetCode Populating Next Right Pointers in Each Node
    LeetCode Construct Binary Tree from Inorder and Postorder Traversal
    LeetCode Reverse Linked List II
    LeetCode Populating Next Right Pointers in Each Node II
    LeetCode Pascal's Triangle
    Palindrome Construct Binary Tree from Preorder and Inorder Traversal
    Pascal's Triangle II
    LeetCode Word Ladder
    LeetCode Binary Tree Zigzag Level Order Traversal
  • 原文地址:https://www.cnblogs.com/zhangleo/p/9887181.html
Copyright © 2011-2022 走看看