zoukankan      html  css  js  c++  java
  • BZOJ3129 SDOI2013方程(容斥原理+扩展lucas)

      没有限制的话算一个组合数就好了。对于不小于某个数的限制可以直接减掉,而不大于某个数的限制很容易想到容斥,枚举哪些超过限制即可。

      一般情况下n、m、p都是1e9级别的组合数没办法算。不过可以发现模数已经被给出,并且这些模数的最大质因子幂都不是很大,那么扩展lucas就可以了。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int 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 T,P,n,n1,n2,m,ans,a[9];
    int p[9],b[9],c[9],s[9],t,f[9][11000];
    void inc(int &x,int y,int p){x+=y;if (x>=p) x-=p;}
    void exgcd(int a,int b,int &x,int &y)
    {
        if (b==0)
        {
            x=1,y=0;
            return;
        }
        exgcd(b,a%b,x,y);
        int t=x;x=y;y=t-a/b*x;
    }
    int inv(int a,int p)
    {
        int x,y;
        exgcd(a,p,x,y);
        return (x+p)%p;
    }
    int ksm(int a,int k,int p)
    {
        if (k==0) return 1;
        int tmp=ksm(a,k>>1,p);
        if (k&1) return 1ll*tmp*tmp%p*a%p;
        else return 1ll*tmp*tmp%p;
    }
    int fac(int n,int i)
    {
        if (n==0) return 1;
        return 1ll*fac(n/p[i],i)*ksm(f[i][c[i]],n/c[i],c[i])%c[i]*f[i][n%c[i]]%c[i];
    }
    int C(int n,int m,int i)
    {
        int s=0;
        for (long long j=p[i];j<=n;j*=p[i]) s+=n/j;
        for (long long j=p[i];j<=m;j*=p[i]) s-=m/j;
        for (long long j=p[i];j<=n-m;j*=p[i]) s-=(n-m)/j;
        if (s>=b[i]) return 0;
        return 1ll*fac(n,i)*inv(fac(m,i),c[i])%c[i]*inv(fac(n-m,i),c[i])%c[i]*ksm(p[i],s,c[i])%c[i];
    }
    int crt()
    {
        int ans=0;
        for (int i=1;i<=t;i++)
        inc(ans,1ll*s[i]*(P/c[i])%P*inv(P/c[i],c[i])%P,P);
        return ans;
    }
    int calc(int n,int m)
    {
        if (n<m) return 0;
        for (int i=1;i<=t;i++)
        s[i]=C(n,m,i);
        return crt();
    }
    void dfs(int k,int s,int m)
    {
        if (k>n1) 
        {
            if (s&1) inc(ans,(P-calc(m-1,n-1))%P,P);
            else inc(ans,calc(m-1,n-1),P);
            return;
        }
        dfs(k+1,s+1,m-a[k]);
        dfs(k+1,s,m);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj3129.in","r",stdin);
        freopen("bzoj3129.out","w",stdout);
        const char LL[]="%I64d";
    #else
        const char LL[]="%lld";
    #endif
        T=read(),P=read();
        if (P==10007) t=1,p[1]=10007,b[1]=1,c[1]=10007;
        else if (P==262203414)
        {
            t=5;
            p[1]=2,p[2]=3,p[3]=11,p[4]=397,p[5]=10007;
            b[1]=1,b[2]=1,b[3]=1,b[4]=1,b[5]=1;
            c[1]=2,c[2]=3,c[3]=11,c[4]=397,c[5]=10007;
        }
        else
        {
            t=3;
            p[1]=5,p[2]=7,p[3]=101;
            b[1]=3,b[2]=3,b[3]=2;
            c[1]=125,c[2]=343,c[3]=10201;
        }
        for (int i=1;i<=t;i++)
        {
            f[i][0]=1;
            for (int j=1;j<=c[i];j++) 
            if (j%p[i]==0) f[i][j]=f[i][j-1];
            else f[i][j]=1ll*f[i][j-1]*j%c[i];
        }
        while (T--)
        {
            n=read(),n1=read(),n2=read(),m=read();
            for (int i=1;i<=n1;i++) a[i]=read();
            for (int i=1;i<=n2;i++) m-=read()-1;
            ans=0;
            if (m>0) dfs(1,0,m);
            cout<<ans<<endl;
        }
        return 0;
    }
  • 相关阅读:
    if..endif 语法
    WordPress程序流程分析
    php锁表
    jQuery入门必须掌握的一些API
    集合栈
    回文链表
    链式A+B
    链表分割
    访问单个节点的删除
    链表中倒数第k个结点
  • 原文地址:https://www.cnblogs.com/Gloid/p/9468101.html
Copyright © 2011-2022 走看看