[1]组合
题目描述
给出组合数 C(n,m) 表示从 n 个元素中选出 m 个元素的方案数。例如 C(5,2)=10,C(4,2)=6。可是当 n,m 比较大的时候,C(n,m) 很大。于是 xiaobo 希望你输出C(n,m)modp 的值。
输入
输入数据第一行是一个正整数 T,表示数据组数;

接下来是 T 组数据,每组数据有 3 个正整数 n,m,p。

对于所有数据,T≤100,1≤m≤n≤109,m≤104,m<p<109,p 是素数。

输出
对于每组数据,输出一个正整数,表示 C(n,m)modp 的结果。
样例输入
2
5 2 3
5 2 61
样例输出
1
10
思路:
Lucas定理模板题,
因为n,m的值太大所以要简化运算, C(m, n) = C(m mod p, n mod p) * C(m / p, n / p) (mod p)

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;

ll fpow(ll a,ll b,ll n){
	if(b==1) return a;
	if(b%2 == 1){
		ll t = fpow(a,b/2,n);
		t = t * t % n;
		t = t * a % n;
		return t; 
	}
	else{
		ll t = fpow(a,b/2,n);
		t = t * t % n;
		return t;
	}
} 

ll comb(ll n,ll m,ll p){
	if(m>n)return 0;
	if(m==0)return 1;
	ll up = 1 ,down = 1;
	for(ll i = 1 ; i <= m ; i++){
		up = (up * (n-i+1)) % p;
		down = (down * i) % p ; 
	} 
	return up * fpow(down,p-2,p) % p;
} 

ll lucas(ll n, ll m ,ll p ){
	if(m==0) return 1;
	return comb(n%p,m%p,p) * lucas(n/p,m/p,p) % p;
}

int main(void)
{
	int t;
	cin>>t;
	while(t--){
		ll n,m,p;
		cin>>n>>m>>p;
		cout<<lucas(n,m,p)<<endl;
	} 
}

[2] 牡牛和牝
题目描述
约翰要带 N 只牛去参加***里的展示活动,这些牛可以是牡牛,也可以是牝牛。牛们要站成一排,但是牡牛是好斗的,为了避免牡牛闹出乱子,约翰决定任意两只牡牛之间至少要有 K 只牝牛。
请计算一共有多少种排队的方法,所有牡牛可以看成是相同的,所有牝牛也一样,答案对 5000011 取模。
输入
一行,输入两个整数 N 和 K。
对于全部数据,1≤N≤105,0≤K<N。
输出
一个整数,表示排队的方法数。
样例输入
4 2
样例输出
6
样例说明:
六种方法如下 :
牝牝牝牝,牡牝牝牝,牝牡牝牝,牝牝牡牝,牝牝牝牡,牡牝牝牡
思路:
, 枚举牡牛的数量m,将总牛数减去至少需要的牝牛数量后记为n,则每种数量的答案就为C(n,m),答案就是把合法答案加起来,即ans=ΣC(n-(i-1)*k,i),

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#define ll long long
using namespace std;
 
const int mod=5000011;
ll n,k,ans;
 
ll ksm(ll a,ll b)
{
    ll ans = 1;
    a = a % mod;
    while(b)
    {
      if(b&1) ans = (ans * a) % mod;
      b >>= 1;
      a = (a * a) % mod;
    }
    return ans % mod;
}
 
ll C(ll n,ll m)
{
    if(m > n) return 0;
	if(m == 0) return 1;
    ll a=1,b=1;
    for(ll i=n-m+1;i<=n;i++)
		a = a * i % mod;
    for(ll i=2;i<=m;i++)
		b = b * i % mod;
    return a * ksm(b,mod-2) % mod; 
}
 
 ll Lucas(ll n,ll m)
{
    if(!m) 
		return 1;
    else 
		return (C(n % mod , m % mod) % mod * Lucas(n / mod , m / mod) % mod) % mod;
}
 
int main(void)
{
    cin>>n>>k;
    for(ll i=0;i<=n;i++)
    {
      ll j=n-(i-1)*k;
      if(j<i)  break;
      ans=(ans+Lucas(j,i))%mod;
    }
    cout<<ans<<endl;
 
    return 0;
}

[3] 方程的解
题目描述
佳佳碰到了一个难题,请你来帮忙解决。对于不定方程
a1+a2+⋯+ak−1+ak=g(x),
其中 k≥2 且 k∈N∗,x 是正整数,
g(x)=xxmod1000(即 xx 除以 1000 的余数),x,k 是给定的数。我们要求的是这个不定方程的正整数解组数。
举例来说,当 k=3,x=2 时,方程的解分别为:
a1=1,a2=1,a3=2
a1=1,a2=2,a3=1
a1=2,a2=1,a3=1
输入
有且只有一行,为用空格隔开的两个正整数,依次为k,x。
对于 40% 数据,答案不超过 1016;
对于全部数据,1≤k≤100,1≤x<231,k≤g(x)。
输出
有且只有一行,为方程的正整数解组数。
样例输入
3 2
样例输出
3
思路:
这题求得是正整数解,只要把计算出来的g(x)拆成若干个1然后插板法就行了,
算g(x)可以用快速幂求解,然后数据很大要用高精度计算不然会wa,


 	#include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int mod=1000;
    int a[10100];
    int k,x;
    
    int mulm(int a,int b){
        if(b==1) return a;
        int t=mulm(a,b>>1);
        t*=t;
        t%=mod;
        if(b%2==1){
            t*=a;
            t%=mod;
        }
        return t;
    }
    
    void comb(int n,int m){
        a[1]=1;
        a[0]=1;
        for(int i=m+1;i<=n;i++){
            for(int j=1;j<=a[0];j++){
                a[j]*=i;
            }
            int tmp=0;
            for(int j=1;j<=a[0];j++){
                tmp+=a[j];
                a[j]=tmp%10;
                tmp/=10;
            }
            while(tmp){
                a[++a[0]]=tmp%10;
                tmp/=10;
            }
        }
        for(int i=2;i<=n-m;i++){
            int tmp=0;
            for(int j=a[0];j>=1;j--){
                tmp*=10;
                tmp+=a[j];
                a[j]=0;
                if(tmp>i){
                    a[j]=tmp/i;
                    tmp%=i;
                }
            }
            while(a[a[0]]==0) a[0]--;
        }
    }
    
    int main(){
        cin>>k>>x;
        x%=mod;
        x=mulm(x,x);
        comb(x-1,k-1);
        for(int i=a[0];i>=1;i--) 
    		cout<<a[i];
        return 0;
    }