1. 程式人生 > >取石子(快速冪,逆元)

取石子(快速冪,逆元)

連結:https://www.nowcoder.com/acm/contest/113/A
來源:牛客網

題目描述

給出四堆石子,石子數分別為a,b,c,d。規定每次只能從堆頂取走石子,問取走所有石子的方案數。

輸入描述:

在一行內讀入四個由空格分隔的整數a,b,c,d, 輸入均為不超過500的正整數

輸出描述:

輸出一個整數表示答案,答案對109+7取模
翻譯過來就是有4個隊的人 人數可能不同  站成一個大隊伍一共用多少種排列方式


四堆石子看作4隊人  4個隊的人排成一排的方案數量  首先總人數全排列,然後去重

因為每個隊伍裡面的人看作是一樣的無區別的

費馬小定理

在模為素數p的情況下,有費馬小定理 
a^(p-1)=1(mod p) 
那麼a^(p-2)=a^-1(mod p) 
也就是說a的逆元為a^(p-2)

而在模不為素數p的情況下,有尤拉定理 
a^phi(m)=1(mod m) (a⊥m) 
同理a^-1=a^(phi(m)-1)

因此逆元x便可以套用快速冪求得了x=a^(phi(m)-1)

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mset(a,b) memset(a,b,sizeof(a))
#define sz size()
#define cl clear()
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define PI 3.1415926535897932384626433832795028841971693993751058209749445923078164
typedef long long ll;
typedef pair<int,int> pr;
const int inf = 99999999;
const double eps = 1e-8;
const int dir4[4][2] = {{-1,0},{1,0},{0,-1},{0,1}};
const int dir8[8][2] = {{1,0},{-1,0},{0,1},{0,-1},{1,1},{1,-1},{-1,1},{-1,-1}};
const int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int monn[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const int mod = 1e9 + 7;
//快速冪 
ll quickPow(ll a,ll b)
{
	ll res = 1;
	while(b)
	{
		if(b & 1)
		{
			res = res * a % mod;
		}
		
		a = a * a % mod;
		
		b >>= 1;
	}
	return res;
}

ll inv(ll x)
{
	ll res = 1;
	res = quickPow(x,mod-2) % mod;
	return res;
}

ll jc(ll a)
{
	ll res = 1;
	for(int i = 1;i <= a;i ++)
	res = res * i % mod;
	return res;
}
int main()
{
	ll a, b, c, d;
	cin >> a >> b >> c >> d;
	ll sum = jc(a+b+c+d);
	cout << sum * inv(jc(a))% mod* inv(jc(b))% mod * inv(jc(c)) % mod* inv(jc(d)) % mod;
	return 0;
}