【CRT】【组合数】Number Theory Special Training T1 eqution 题解

Problem 1.

Input file: eqution.in
Output file: eqution.out
Time limit: 1 second
Memory limit: 256 MB
Mr. Hu 又来让你帮忙解方程了。
方程是这样的:
x1 + x1 + x3 + + xn = m (xi 0 81 i n)
Mr. Hu 希望你求出这个n 元一次方程的整数解有多少个,因为解的个数有可能变得很大,所以Mr. Hu
只需要你输出解的个数取模于mod。
Input
第1 行,包含一个整数:T,表示询问个数
接下来T 行,每行包含三个整数:n m mod
Output
输出T 行,每行输出解的个数模对应mod
Sample
eqution.in eqution.out
12
3 13
4
Note
样例中,解分别是:(3; 0); (2; 1); (1; 2); (0; 3)
• 对于30% 的数据,1 n;m 6,mod = 108 + 7,T = 1
• 对于70% 的数据,1 n;m 103,n + m mod 108 + 7,mod 是一个素数,1 T 100
• 对于余下30% 的数据,1 n;m 103,n+m p; q 104,mod = pq,p; q 是素数,1 T 103

1.1 30% 数据
暴力,这时答案本身很小,所以只需要写一个dfs。
1.2 70% 数据
这个问题等价于“将m 个相同的球放进n 个不同的盒子中”的方案数,
也可以暴力乘+逆元。
复杂度后者好点(因为模数不同,前者每次都要推一遍)
1.3 余下30% 数据
用公式推应该会超时,只能用后面那个,求逆元可以用扩展欧几里得,也可以
欧拉定理。当然也可以在在模p 和模q 时
答案求出来,再用中国剩余定理合并。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<stack>
#define INF 2100000000
#define LL long long
#define clr(x) memset(x,0,sizeof(x))
#define ms(a,x) memset(x,a,sizeof(x))
#ifdef win32
#define AUTO "%I64d"
#else
#define AUTO "%lld"
#endif

using namespace std;

int t,n,m,mod;

template <class T> void exgcd(T a, T b, T& d, T& x, T& y) {
    if(!b) d = a, x = 1, y = 0;
    else exgcd(b, a%b, d, y, x), y -= (a/b)*x;
}

template <class T> inline T inv(T a, T n) {
    T d,x,y;
    exgcd(a, n, d, x, y);
    return d == 1 ? ((x+n)%n) : (-1);
}

inline int Comb(int x, int y) {
    LL ret = 1, b = 1;
    for(int i = y; i > y - x; i--) (ret *= i) %= mod;
    for(int i = 2; i <= x; i++) (b *= i) %= mod;
    (ret *= inv(b, (LL)mod)) %= mod;
    return (int)ret;
}

int main() {
    freopen("equation.in","r",stdin);
    freopen("equation.out","w",stdout);
    scanf("%d",&t);
    while(t--) {
        scanf("%d%d%d",&n,&m,&mod);
        printf("%d\n", Comb(n-1, n+m-1));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值