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表示这个测试点内的数据组数,p的含义见题目描述。
对于每组数据,第一行四个非负整数n,n1,n2,m。
第二行nl+n2个正整数,表示A1..n1+n2。请注意,如果n1+n2等于0,那么这一行会成为一个空行。

输出格式

共T行,每行一个正整数表示取模后的答案。

输入样例

3 10007

3 1 1 6

3 3

3 0 0 5

3 1 1 3

3 3

输出样例

3

6

0

【样例说明】

对于第一组数据,三组解为(1,3,2),(1,4,1),(2,3,1)

对于第二组数据,六组解为(1,1,3),(1,2,2),(1,3,1),(2,1,2),(2,2,1),(3,1,1)

提示

n < = 10^9 , n1 < = 8 , n2 < = 8 , m < = 10^9 ,p<=437367875

对于l00%的测试数据: T < = 5,1 < = A1..n1_n2 < = m,n1+n2 < = n

题解

组合数经典套路:

对于下限的限制,我们预先分配那么多的数,就去掉了这个下限

对于上限的限制,我们容斥一下哪些数超过了限制,就去掉了上限

被卡常卡哭了,,

膜了一下别人的代码才发现扩展Lucas在计算前预处理一下阶乘会快很多

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<‘ ‘; puts("");
#define res register
using namespace std;
const int maxn = 11000,maxm = 100005,INF = 1000000000;
inline int read(){
    int out = 0,flag = 1; char c = getchar();
    while (c < 48 || c > 57){if (c == ‘-‘) flag = -1; c = getchar();}
    while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    return out * flag;
}
int md,A[11];
int pi[11],pk[11],cnt,fac[maxn];
void pre(int pi,int pk){
    fac[0] = 1;
    for (int i = 1; i <= pk; i++)
        if (i % pi) fac[i] = 1ll * fac[i - 1] * i % pk;
        else fac[i] = fac[i - 1];
}
void init(){
    int x = md;
    for (res int i = 2; i * i <= x; i++)
        if (x % i == 0){
            ++cnt; pi[cnt] = i; pk[cnt] = 1;
            while (x % i == 0) pk[cnt] *= i,x /= i;
        }
    if (x - 1) ++cnt,pi[cnt] = pk[cnt] = x;
}
inline int qpow(int a,int b,int md){
    int ans = 1;
    for (; b; b >>= 1,a = 1ll * a * a % md)
        if (b & 1) ans = 1ll * ans * a % md;
    return ans % md;
}
void exgcd(LL a,LL b,LL& d,LL& x,LL &y){
    if (!b) {x = 1; y = 0; d = a;}
    else exgcd(b,a % b,d,y,x),y -= a / b * x;
}
inline LL inv(LL a,LL P){
    if (!a) return 0;
    LL d,x,y; exgcd(a,P,d,x,y);
    x = (x % P + P) % P; if (!x) x += P;
    return x;
}
inline LL Fac(LL n,LL pi,LL pk){
    if (!n) return 1;
    int ans = qpow(fac[pk],n / pk,pk);
    return 1ll * ans * fac[n % pk] % pk * Fac(n / pi,pi,pk) % pk;
}
inline int C(int n,int m,int pi,int pk){
    if (m > n) return 0;
    int a = Fac(n,pi,pk),b = Fac(m,pi,pk),c = Fac(n - m,pi,pk),ans,k = 0;
    for (res int i = n; i; i /= pi) k  += i / pi;
    for (res int i = m; i; i /= pi) k  -= i / pi;
    for (res int i = n - m; i; i /= pi) k  -= i / pi;
    ans = 1ll * a * inv(b,pk) % pk * inv(c,pk) % pk * qpow(pi,k,pk) % pk;
    return 1ll * ans * (md / pk) % md * inv(md / pk,pk) % md;
}
inline int exlucas(int n,int m){
    if (m > n) return 0;
    int ans = 0;
    for (res int i = 1; i <= cnt; i++)
        pre(pi[i],pk[i]),ans = (ans + C(n,m,pi[i],pk[i])) % md;
    return ans;
}
void solve(){
    int N = read(),n1 = read(),n2 = read(),M = read();
    M -= N;
    for (res int i = 1; i <= n1; i++) A[i] = read();
    for (res int i = 1; i <= n2; i++) M -= read() - 1;
    int maxv = (1 << n1) - 1;
    int re = 0;
    for (res int s = 0; s <= maxv; s++){
        int m = M,pos = 1;
        for (res int i = 1,t = s; i <= n1; i++, t >>= 1)
            if (t & 1) m -= A[i],pos = -pos;
        if (m + N - 1 < 0) continue;
        re = (re + 1ll * pos * exlucas(m + N - 1,N - 1) % md) % md;
    }
    re = (re % md + md) % md;
    printf("%d\n",re);
}
int main(){
    int T = read(); md = read();
    init();
    while (T--) solve();
    return 0;
}

原文地址:https://www.cnblogs.com/Mychael/p/8970968.html

时间: 2024-10-11 07:17:45

BZOJ3129 [Sdoi2013]方程 【扩展Lucas】的相关文章

【模板】扩展Lucas随想

扩展Lucas解决的还是一个很Simple的问题: 求:$C_{n}^{m} \; mod \; p$. 其中$n,m$都会比较大,而$p$不是很大,而且不一定是质数. 扩展Lucas可以说和Lucas本身并没有什么关系,重要的是中国剩余定理.扩展Lucas这个算法中教会我们的除了算组合数,还有在模数不是质数的时候,往往可以用$CRT$来合并答案. 将原模数质因数分解:$P = \prod_{i = 1}^{m} p_{i}^{k_{i}}$. 列出$m$个同余方程,第$i$个形如:$C_{n}

●BZOJ 3129 [Sdoi2013]方程

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

CF.100633J.Ceizenpok&#39;s formula(扩展Lucas)

题目链接 ->扩展Lucas //求C_n^k%m #include <cstdio> typedef long long LL; LL FP(LL x,LL k,LL p) { LL t=1ll; for(; k; k>>=1,x=x*x%p) if(k&1) t=t*x%p; return t; } void Exgcd(LL a,LL b,LL &x,LL &y) { if(!b) x=1ll, y=0ll; else Exgcd(b,a%b,y

BZOJ.2142.礼物(扩展Lucas)

题目链接 答案就是C(n,m1) * C(n-m1,m2) * C(n-m1-m2,m3)...(mod p) 使用扩展Lucas求解. 一个很简单的优化就是把pi,pi^ki次方存下来,因为每次分解p都是很慢的. 注意最后p不为1要把p再存下来!(质数) COGS 洛谷上的大神写得快到飞起啊QAQ 就这样吧 //836kb 288ms #include <cmath> #include <cstdio> typedef long long LL; int cnt,P[500],P

[BZOJ2142]礼物(扩展Lucas)

2142: 礼物 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 2286  Solved: 1009[Submit][Status][Discuss] Description 一年一度的圣诞节快要来到了.每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物.不同的人物在小E 心目中的重要性不同,在小E心中分量越重的人,收到的礼物会越多.小E从商店中购买了n件礼物,打算送给m个人 ,其中送给第i个人礼物数量为wi.请你帮忙计算出送礼物的方案数(

BZOJ2142 礼物 【扩展Lucas】

题目 一年一度的圣诞节快要来到了.每年的圣诞节小E都会收到许多礼物,当然他也会送出许多礼物.不同的人物在小E 心目中的重要性不同,在小E心中分量越重的人,收到的礼物会越多.小E从商店中购买了n件礼物,打算送给m个人 ,其中送给第i个人礼物数量为wi.请你帮忙计算出送礼物的方案数(两个方案被认为是不同的,当且仅当存在某 个人在这两种方案中收到的礼物不同).由于方案数可能会很大,你只需要输出模P后的结果. 输入格式 输入的第一行包含一个正整数P,表示模: 第二行包含两个整整数n和m,分别表示小E从商

扩展lucas定理

i64 POW(i64 a,i64 b,i64 mod) { i64 ans=1; while(b) { if(b&1) ans=ans*a%mod; a=a*a%mod; b>>=1; } return ans; } i64 POW(i64 a,i64 b) { i64 ans=1; while(b) { if(b&1) ans=ans*a; a=a*a; b>>=1; } return ans; } i64 exGcd(i64 a,i64 b,i64 &

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

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

BZOJ 3129 SDOI2013 方程

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