[机房练习赛4.6] equation 中国剩余定理

Problem 1. eqution

Input file: eqution.in
Output file: eqution.out
Time limit: 1 second
Memory limit: 256 MB

Hfu 又来让你帮忙解方程了。
方程是这样的:
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
12
3 13
eqution.out
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

#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
bool isprime( int x ){
    for( int i = 2; i*i <= x; i++ )
        if( x % i == 0 ) return false;
    return true;
} 
void exgcd( ll a, ll b, ll &d, ll &x, ll &y ){
    if( b == 0 ){
        x = 1;y = 0;d = a;return ;
    } else{
        ll x1,y1;
        exgcd( b, a%b, d, x1, y1 );
        x = y1;
        y = x1-(a/b)*y1;
    }
}
ll inverse( ll a, ll mod ){
    ll d,x,y;
    exgcd( a, mod, d, x, y );
    if( d < 0 ) d = -d; x = -x; y = -y;
    return ( x % mod + mod ) % mod; 
}
ll comb( int n, int m, int p ) {
    ll rt = 1;
    for( int i = 1; i <= m; i++ ) {
        rt = rt * (n + 1 - i) % p;
        rt = rt * inverse( i, p ) % p;
    }
    return rt;
}
void merge( ll a1, ll m1, ll a2, ll m2, ll &a, ll &m ){
    ll t1,t2,d;
    exgcd( m1, -m2, d, t1, t2 );
    t1 = (t1 % m2 + m2) % m2;
    t1 = t1 * (a2 - a1) / d;
    m = m1 * m2;
    a = a1 + (m1 * t1) % m;
    a = (a % m + m) % m;
}
int main(){
    freopen("equation.in","r",stdin);
    freopen("equation.out","w",stdout);
    int T;
    scanf("%d", &T);
    while(T--){
        int n, m, mod;
        scanf("%d%d%d", &n, &m, &mod );
        if( isprime(mod) ){
            printf("%I64d\n",comb( n+m-1, m, mod ));
        }else{
            int p,q;
            for( int i = 2; i * i <= mod; i++ )
                if( mod % i == 0 ){
                    p = i; q = mod/p; break;
                }
            ll a1 = comb( n + m - 1, m, p );
            ll a2 = comb( n + m - 1, m, q );
            ll a,m;
            merge( a1, p, a2, q, a, m );
            printf("%I64d\n", a);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值