P3301 [SDOI2013]方程

思路

容斥的挺好的练习题
对于第二个条件,可以直接使m减去suma2,使得第二个条件舍去,然后m再减去n,使得问题转化成有n1个变量要满足小于等于某个数的条件,其他的随便取,求整数解的个数
对n1,以2^n的复杂度枚举至少哪些不符合限制,然后容斥(至少0个-至少1个+至少2个....)
然后用隔板法可以得到每一次答案为
\[
\left(\begin{matrix}m-midt-1\\n-1\end{matrix}\right)
\]
注意本题模数不是质数,需要EXLucas,同时由于本题卡时间,所以要预处理MOD的质因数和mul函数要用的阶乘

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;
int pow(int a,int b,int MOD){
    int ans=1;
    while(b){
        if(b&1)
            ans=(1LL*ans*a)%MOD;
        a=(1LL*a*a)%MOD;
        b>>=1;
    }
    return ans;
}
int exgcd(int a,int b,int &x,int &y){
    if(b==0){
        x=1;
        y=0;
        return a;
    }
    int req=exgcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-a/b*y;
    return req;
}
int inv(int a,int p){
    if(!a)
        return 0;
    int x,y;
    exgcd(a,p,x,y);
    x=((x%p+p)%p);
    if(!x)
        x+=p;
    return x;
}
int f[10210];
int mul(int n,int pi,int pk){//get n!/pi^a%p^k
    if(n<pi)
        return f[n];
    return 1LL*pow(f[pk-1],n/pk,pk)*f[n%pk]%pk*mul(n/pi,pi,pk)%pk;
}
int C(int n,int m,int Mod,int pi,int pk){
    if(m>n)
        return 0;
    f[0]=1;
    for(int i=1;i<=pk;i++)
        if(i%pi)
            f[i]=(f[i-1]*i)%pk;
        else
            f[i]=f[i-1];
    int jcn=mul(n,pi,pk),jcm=mul(m,pi,pk),jcnm=mul(n-m,pi,pk),k=0;
    for(int i=n;i;i/=pi)
        k+=i/pi;
    for(int i=m;i;i/=pi)
        k-=i/pi;
    for(int i=n-m;i;i/=pi)
        k-=i/pi;
    int ans=1LL*jcn*inv(jcm,pk)%pk*inv(jcnm,pk)%pk*pow(pi,k,pk)%pk;
    return 1LL*ans*(Mod/pk)%Mod*inv(Mod/pk,pk)%Mod;
}
int exLucas(int n,int m,int Mod){
    int ans=0;
    if(Mod==10007){
        ans=(ans+C(n,m,Mod,10007,10007))%Mod;
    }
    else if(Mod==262203414){
        ans=(ans+C(n,m,Mod,2,2)%Mod+C(n,m,Mod,3,3)%Mod+C(n,m,Mod,11,11)%Mod+C(n,m,Mod,397,397)%Mod+C(n,m,Mod,10007,10007)%Mod)%Mod;
    }
    else{
        ans=(ans+C(n,m,Mod,5,125)+C(n,m,Mod,7,343)+C(n,m,Mod,101,10201))%Mod;
    }
    return ans;
}
int n,n1,n2,m,A[20],MOD,ans,T,sum2;
int bitcount(int x){
    int ans=0;
    while(x){
        ans++;
        x&=(x-1);
    }
    return ans;
}
int bi[(1<<9)];
signed main(){
    scanf("%lld %lld",&T,&MOD);
    for(int i=0;i<(1<<8);i++)
        bi[i]=bitcount(i);
    while(T--){
        memset(A,0,sizeof(A));
        ans=0;
        sum2=0;
        scanf("%lld %lld %lld %lld",&n,&n1,&n2,&m);
        for(int i=1;i<=n1+n2;i++){
            scanf("%lld",&A[i]);
            if(i>n1)
                sum2+=A[i]-1;
        }
        m-=sum2;
        for(int i=0;i<(1<<(n1));i++){
            int midt=0,midcnt=0;
            for(int j=1;j<=n1;j++)
                if((i>>(j-1))&1)
                    midt+=A[j],midcnt++;
            ans=(ans+(1LL*((bi[i]&1)?-1:1)*exLucas(m-midt-1,n-1,MOD)%MOD+MOD))%MOD;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/dreagonm/p/10534478.html

时间: 2024-10-11 18:18:24

P3301 [SDOI2013]方程的相关文章

[BZOJ 3129] [Sdoi2013] 方程 【容斥+组合数取模+中国剩余定理】

题目链接:BZOJ - 3129 题目分析 使用隔板法的思想,如果没有任何限制条件,那么方案数就是 C(m - 1, n - 1). 如果有一个限制条件是 xi >= Ai ,那么我们就可以将 m 减去 Ai - 1 ,相当于将这一部分固定分给 xi,就转化为无限制的情况了. 如果有一些限制条件是 xi <= Ai 呢?直接来求就不行了,但是注意到这样的限制不超过 8 个,我们可以使用容斥原理来求. 考虑容斥:考虑哪些限制条件被违反了,也就是说,有哪些限制为 xi <= Ai 却是 xi

BZOJ3129 [Sdoi2013]方程 【扩展Lucas】

题目 给定方程 X1+X2+. +Xn=M 我们对第l..N1个变量进行一些限制: Xl < = A X2 < = A2 Xn1 < = An1 我们对第n1 + 1..n1+n2个变量进行一些限制: Xn1+l > = An1+1 Xn1+2 > = An1+2 Xnl+n2 > = Anl+n2 求:在满足这些限制的前提下,该方程正整数解的个数. 答案可能很大,请输出对p取模后的答案,也即答案除以p的余数. 输入格式 输入含有多组数据,第一行两个正整数T,p.T表示

BZOJ 3129 SDOI2013 方程

如果没有限制,答案直接用隔板法C(m-1,n-1) 对于>=x的限制,我们直接在对应位置先放上x-1即可,即m=m-(x-1) 对于<=x的限制,由于限制很小我们可以利用容斥原理将它转化为上面的>=x的限制 即减去1个不满足的 加上2个不满足的 减去3个不满足的 …… 之后就是组合数的计算,对于一个非常大的模数,我们可以将它唯一分解,之后CRT还原即可 但是我们有可能不存在逆元,数据范围不允许我们递推计算组合数 我们知道没有逆元当且仅当(a,p)不互素,我们可以将阶乘分成两部分:互素和不

BZOJ 3129 [Sdoi2013]方程 不定方程解的个数+组合数取模

题意:链接 方法:不定方程解的个数+组合数取模 解析: 先看n1与n2的部分的限制. 对于后半部分的限制来说,我们直接减去An1+i?1就可以转化一下求正整数解. 但是前半部分呢? 跟上一道猴子那个很像. 所以我们容斥搞就行了. 但是这道题好像不好写的地方不在这? 这题TMD不就是礼物吗! 大组合数取模如何取? 请参见我<BZOJ 礼物>的题解. 另外吐槽题干 明明是X1+X2+-+Xn=m 并不是小于等于 代码: #include <cstdio> #include <cs

●BZOJ 3129 [Sdoi2013]方程

题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3129 题解: 容斥,扩展Lucas,中国剩余定理 先看看不管限制,只需要每个位置都是正整数时的方案数的求法.假设有 N 个未知数,加起来的和为 M.转化一下问题变为:"小球分配" 有 M 个相同的小球,放在 N 个盒子里,且每个盒子至少有一个的方案数. 那么方案数为 ${C}_{M-1}^{N-1}$怎么理解这个式子呢?"插隔板法".使 M个小球放在一排,考虑

计数类问题专题

主要是前两天被uoj的毛爷爷的题虐的不轻,心里很不爽啊,必须努力了,, 计数类问题分为:1.组合数学及数论计数 2.dp:状态压缩dp,插头轮廓线dp,树形dp,数位dp,普通dp 3.容斥原理 4.polya原理 5.图论计数 6.生成函数 7.其它(生成树计数等等) 本文主要研究前3个内容 考虑基本计数原理:加法原理,减法原理,乘法原理,除法原理 计数的基本原则:结果不重不漏 加法原理比较自然,中间过程有时减法原理 考虑到无向,有向图的各种量值(生成树之类)计数,状态压缩dp解决 论文:ht

【BZOJ 3122】 [Sdoi2013]随机数生成器 (BSGS)

3122: [Sdoi2013]随机数生成器 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1442  Solved: 552 Description Input 输入含有多组数据,第一行一个正整数T,表示这个测试点内的数据组数. 接下来T行,每行有五个整数p,a,b,X1,t,表示一组数据.保证X1和t都是合法的页码. 注意:P一定为质数 Output 共T行,每行一个整数表示他最早读到第t页是哪一天.如果他永远不会读到第t页,输出-1. Sa

利用图形窗口分割法将极坐标方程:r=cos(θ/3)+1/9用四种绘图方式画在不同的窗口中

利用图形窗口分割法将极坐标方程:r=cos(θ/3)+1/9用四种绘图方式画在不同的窗口中. 解:MATLAB指令: theta=0:0.1:6*pi;rho=cos(theta/3)+1/9; >> polar(theta,rho) >> >> plot(theta,rho) >> semilogx(theta,rho) >> grid >> hist(rho,15) 结果分别如下图: 图1 图2 图3 图4

BZOJ 1041: [HAOI2008]圆上的整点【数论,解方程】

1041: [HAOI2008]圆上的整点 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4210  Solved: 1908[Submit][Status][Discuss] Description 求一个给定的圆(x^2+y^2=r^2),在圆周上有多少个点的坐标是整数. Input 只有一个正整数n,n<=2000 000 000 Output 整点个数 Sample Input 4 Sample Output 4 HINT 科普视频 So