Challenge: Cheese and Random Toppings
Subdomeniu: Number Theory (number-theory)
Scor cont: 30.0 / 30
Submission status: Accepted
Submission score: 1.0
Submission ID: 464724872
Limbaj: cpp14
Link challenge: https://www.hackerrank.com/challenges/cheese-and-random-toppings/problem
Cerinta
*Waiter:* Good day, sir! What would you like to order?
*Lucas:* One Cheese & Random Toppings (CRT) pizza for me, please.
*Waiter:* Very good, sir. There are $N$ toppings to choose from, but you can choose only $R$ toppings.
*Lucas:* Hmm, let's see...
...Then Lucas started writing down all the ways to choose *R* toppings from *N* toppings in a piece of napkin. Soon he realized that it's impossible to write them all, because there are a lot. So he asked himself: **How many ways are there to choose exactly $R$ toppings from $N$ toppings?**
Since Lucas doesn't have all the time in the world, he only wished to calculate the answer **modulo $M$**, where *M* is a squarefree number whose prime factors are each less than *50*.
Fortunately, Lucas has a Wi-Fi-enabled laptop with him, so he checked the internet and discovered the following useful links:
[Lucas' theorem](http://en.wikipedia.org/wiki/Lucas'_theorem)
[Chinese remainder theorem (CRT)](http://en.wikipedia.org/wiki/Chinese_remainder_theorem#Existence_and_uniqueness)
**Input Format**
The first line of input contains $T$, the number of test cases. The following lines describe the test cases.
Each test case consists of one line containing three space-separated integers: $N$, $R$ and $M$.
**Constraints**
$1 \le T \le 200$
$1 \le M \le 10^9$
$1 \le R \le N \le 10^9$
$M$ is squarefree and its prime factors are less than $50$
**Output Format**
For each test case, output one line containing a single integer: the number of ways to choose $R$ toppings from $N$ toppings, modulo $M$.
**Sample Input**
6
5 2 1001
5 2 6
10 5 15
20 6 210
13 11 21
10 9 5
**Sample Output**
10
4
12
120
15
0
**Explanation**
*Case 1 and 2*: Lucas wants to choose *2* toppings from *5* toppings. There are ten ways, namely (assuming the toppings are **A**, **B**, **C**, **D** and **E**):
**AB**, **AC**, **AD**, **AE**, **BC**, **BD**, **BE**, **CD**, **CE**, **DE**
Thus,
*Case 1*: $10 \bmod 1001 = 10$
*Case 2*: $10 \bmod 6 = 4$
*Case 6*: We can choose *9* toppings from *10* by removing only one from our choice. Thus, we have ten ways and $10 \bmod 5 = 0$
Cod sursa
#include <bits/stdc++.h>
using namespace std;
#define SIZE 100
#define inv(a,m) fpow(a,m-2,m)
typedef long long int ll;
vector<int> primes;
void sieve() {
char* s = new char [SIZE];
int i, j;
for (i = 2; i < SIZE; s[i++] = 1);
s[0] = s[1] = 0;
for (i = 2; i*i < SIZE; ++i) {
if (s[i]) {
for (j = i*i; j < SIZE; j += i) {
s[j] = 0;
}
}
}
for (i = 2; i < SIZE; ++i) {
if (s[i]) {
primes.push_back(i);
}
}
delete [] s;
}
ll fpow(ll a, ll b, ll mod) {
ll res = 1;
while (b) {
if (b & 1)
res = (res * a) % mod;
b >>= 1;
a = (a*a) % mod;
}
return res;
}
ll fact(ll r, ll mod) {
ll res = 1;
for (ll i = 2; i <= r; ++i) {
res = (res * i) % mod;
}
return res;
}
ll comb(ll n, ll r, ll mod) {
ll res = inv(fact(r, mod), mod);
ll nf = 1;
for (ll i = 0; i < r; ++i) {
nf = (nf * (n-i)) % mod;
}
res = (nf * res) % mod;
return res;
}
ll crt(vector<ll> a, vector<ll> p, ll mod) {
/**
* Calculates CRT 'x' such that
* x = a1 (mod p1), x = a2 (mod p2), ...
* a is obtained from lucas
*/
ll x = 0, ni;
for (int i = 0; i < p.size(); ++i) {
ni = mod / p[i];
x += ni * inv(ni, p[i]) * a[i];
}
return x;
}
ll lucas(ll n, ll r, ll p) {
ll res = 1;
while (n > 0) {
res = (res * comb(n % p, r % p, p)) % p;
n /= p;
r /= p;
}
return res;
}
ll nCr(ll n, ll r, ll mod) {
vector<ll> p;
vector<ll> a;
for (int i : primes) {
if (mod % i == 0) {
p.push_back(i);
}
}
for (int i = 0; i < p.size(); ++i) {
a.push_back(lucas(n, r, p[i]));
}
return crt(a, p, mod) % mod;
}
int main() {
int t;
ll n, r, mod;
sieve();
scanf("%i", &t);
while (t--) {
scanf("%lli %lli %lli", &n, &r, &mod);
printf("%lli\n", nCr(n, r, mod));
}
return 0;
}
HackerRank Number Theory – Cheese and Random Toppings
