2020.7.22【算协集训】容斥原理+组合计数

网页链接:传送门
密码:hpuacm

A - Ekka Dokka (LightOJ - 1116)

Ekka and his friend Dokka decided to buy a cake. They both love cakes and that’s why they want to share the cake after buying it. As the name suggested that Ekka is very fond of odd numbers and Dokka is very fond of even numbers, they want to divide the cake such that Ekka gets a share of N square centimeters and Dokka gets a share of M square centimeters where N is odd and M is even. Both N and M are positive integers.
They want to divide the cake such that N * M = W, where W is the dashing factor set by them. Now you know their dashing factor, you have to find whether they can buy the desired cake or not.
Input
Input starts with an integer T (≤ 10000), denoting the number of test cases.
Each case contains an integer W (2 ≤ W < 263). And W will not be a power of 2.
Output
For each case, print the case number first. After that print “Impossible” if they can’t buy their desired cake. If they can buy such a cake, you have to print N and M. If there are multiple solutions, then print the result where M is as small as possible.

Sample InputSample Output
3
10
5
12
Case 1: 5 2
Case 2: Impossible
Case 3: 3 4
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int T;
ll W,M;
int main()
{
	scanf("%d",&T);
	for(int i=1;i<=T;i++)
	{
		scanf("%lld",&W);
		printf("Case %d: ",i);
		if(W%2!=0)	printf("Impossible\n");
		else
		{
			M=1;
			while(W%2==0)
			{
				M*=2;
				W/=2;
			}
			printf("%lld %lld\n",W,M);
		}
	}
	return 0;
}

B - How many integers can you find (HDU - 1796)

Now you get a number N, and a M-integers set, you should find out how many integers which are small than N, that they can divided exactly by any integers in the set. For example, N=12, and M-integer set is {2,3}, so there is another set {2,3,4,6,8,9,10}, all the integers of the set can be divided exactly by 2 or 3. As a result, you just output the number 7.
Input
There are a lot of cases. For each case, the first line contains two integers N and M. The follow line contains the M integers, and all of them are different from each other. 0<N<2^31,0<M<=10, and the M integer are non-negative and won’t exceed 20.
Output
For each case, output the number.

Sample InputSample Output
12 2
2 3
7
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
ll N,M,a[30],sum;
ll gcd(ll a,ll b)
{
	return b==0?a:gcd(b,a%b);
}
ll lcm(ll a,ll b)
{
	return a*b/gcd(a,b);
}
int main()
{
	while(~scanf("%lld%lld",&N,&M))
	{
		ll t,num=0;
		for(int i=0;i<M;i++)
		{
			scanf("%lld",&t);
			if(t>0 && t<N)
			{
				a[num++]=t;
			}
		}
		sum=0;
		for(int i=1;i<(1<<num);i++)
		{
			ll mul=1,cnt=0;
			for(int j=0;j<num;j++)
			{
				if(1&(i>>j))
				{
					mul=lcm(mul,a[j]);
					cnt++;
				}
			}
			if(cnt&1)
			{
				sum+=(N-1)/mul;
			}
			else
			{
				sum-=(N-1)/mul;
			}
		}
		printf("%lld\n",sum);
	}
	return 0;
}

C - Co-prime (HDU - 4135)

Given a number N, you are asked to count the number of integers between A and B inclusive which are relatively prime to N.
Two integers are said to be co-prime or relatively prime if they have no common positive divisors other than 1 or, equivalently, if their greatest common divisor is 1. The number 1 is relatively prime to every integer.
Input
The first line on input contains T (0 < T <= 100) the number of test cases, each of the next T lines contains three integers A, B, N where (1 <= A <= B <= 1015) and (1 <=N <= 109).
Output
For each test case, print the number of integers between A and B inclusive which are relatively prime to N. Follow the output format below.

Sample InputSample OutputHint
2
1 10 2
3 15 5
Case #1: 5
Case #2: 10
In the first test case, the five integers in range [1,10] which are relatively prime to 2 are {1,3,5,7,9}.
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
int T;
ll A,B,N,a[10000],m,sum;
int main()
{
	scanf("%d",&T);
	for(int i=1;i<=T;i++)
	{
		scanf("%lld%lld%lld",&A,&B,&N);
		memset(a,0,sizeof(a));
		m=0;
		for(int j=2;j<=sqrt(N);j++)
		{
			if(N%j==0)
				a[++m]=j;
			while(N%j==0)
					N/=j;
		}
		if(N>1)
			a[++m]=N;
		sum=0;
		for(int j=1;j<(1<<m);j++)
		{
			ll mul=1,cnt=0;
			for(int k=0;k<m;k++)
			{
				if(1&(j>>k))
				{
					mul*=a[k+1];
					cnt++;
				}
			}
			if(cnt&1)
			{
				sum+=B/mul;
				sum-=(A-1)/mul;
			}
			else
			{
				sum-=B/mul;
				sum+=(A-1)/mul;
			}
		}
		printf("Case #%d: %lld\n",i,B-A+1-sum);
	}
	return 0;
}

D - 计算组合数 (计蒜客 - T1305)

给出两个非负整数 n 和 m ,编写程序计算组合数 C(n,m)的值。
输入格式
一行两个空格隔开的非负整数 n,m。
输出格式
输出一个数表示 C(n,m)。
数据范围
0<n≤20,0≤m≤n。

Sample InputSample Output
5 210
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
ll n,m;
ll C(ll n,ll k)
{
	if(k>n)	return 0;
	if(k>n-k)	k=n-k;
	ll m=1,s=1;
	for(int i=0;i<k;i++)
	{
		m=m*(n-i);
		s=s*(i+1);
	}
	return m/s;
}
int main()
{
	while(~scanf("%lld%lld",&n,&m))
	{
		printf("%lld\n",C(n,m));
	}
	return 0;
}

E - Binomial Showdown (POJ - 2249)

In how many ways can you choose k elements out of n elements, not taking order into account?
Write a program to compute this number.
Input
The input will contain one or more test cases.
Each test case consists of one line containing two integers n (n>=1) and k (0<=k<=n).
Input is terminated by two zeroes for n and k.
Output
For each test case, print one line containing the required number. This number will always fit into an integer, i.e. it will be less than 231.
Warning: Don’t underestimate the problem. The result will fit into an integer - but if all intermediate results arising during the computation will also fit into an integer depends on your algorithm. The test cases will go to the limit.

Sample InputSample Output
4 2
10 5
49 6
0 0
6
252
13983816
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
ll n,k;
ll C(ll n,ll k)
{
	if(k>n)	return 0;
	if(k>n-k)	k=n-k;
	ll m=1,s=1;
	for(int i=0;i<k;i++)
	{
		m=m*(n-i);
		m/=(i+1);
	}
	return m/s;
}
int main()
{
	while(~scanf("%lld%lld",&n,&k))
	{
		if(n==0 && k==0)	break;
		printf("%lld\n",C(n,k));
	}
	return 0;
}

F - 组合数 (计蒜客 - T1868)

蒜头君萌上了组合数,现在他很想知道 ∑ i = 0 n C n i \sum_{i=0}^{n}C_{n}^{i} i=0nCni 是多少,其中 i 为偶数, C n i C_{n}^{i} Cni 是组合数,表示 n 个物品无顺序选取 i 个的方案数。
由于答案可能很大,请输出答案对 6662333 的余数。
输入格式
一个整数 n (1≤n≤1018)。
输出格式
一个整数,表示答案对 6662333 取模的结果。

Sample InputSample Output
516
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
const int mod=6662333;
ll ksm(ll a,ll b)
{
	ll res=1;
	while(b)
	{
		if(b&1)	res=res*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return res;
}
int main()
{
	ll n,sum=0;
	scanf("%lld",&n);
	printf("%lld",ksm(2,n-1)%mod);
	return 0;
}

G - 求组合数 (计蒜客 - T1984)

从 n 个不同元素中,任取 m(m≤n) 个元素并成一组,叫做从 n 个不同元素中取出 m 个元素的一个组合;从 n 个不同元素中取出 m(m≤n) 个元素的所有组合的个数,叫做从 n 个不同元素中取出 m 个元素的组合数,记为 C n m C_{n}^{m} Cnm
组合数的计算方法为 C n m = n ! m ! ( n − m ! ) C_{n}^{m}=\frac{n!}{m!(n−m!)} Cnm=m!(nm!)n!,其中 ! 表示阶乘。同时组合数还满足 C n m = C n − 1 m − 1 + C n − 1 m C_{n}^{m}=C_{n-1}^{m-1}+C_{n-1}^{m} Cnm=Cn1m1+Cn1m这个性质。
请你编程求解组合数 C n m C_{n}^{m} Cnm 的值,由于结果可能很大,输出结果对 1000000007 取模的结果。
输入格式
输入一行两个整数 n(1≤n≤2000),m(0≤m≤n)。
输出格式
输出 C n m C_{n}^{m} Cnm 对 1000000007 取模的结果。

Sample Input1Sample Output1
5 210
Sample Input2Sample Output2
100 50538992043
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1e6+10;
const int mod=1000000007;
ll ksm(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 C(ll n,ll k)
{
	if(k>n)	return 0;
	if(k>n-k)	k=n-k;
	ll m=1,s=1;
	for(int i=0;i<k;i++)
	{
		m=m*(n-i)%mod;
		s=s*(i+1)%mod;
	}
	return m*ksm(s,mod-2)%mod;
}
ll lucas(ll a,ll b)
{
	if(a<mod && b<mod)	return C(a,b);
	else	return C(a%mod,b%mod)*lucas(a/mod,b/mod)%mod;
}
int main()
{
	ll n,m,sum=0;
	scanf("%lld%lld",&n,&m);
	printf("%lld",lucas(n,m)%mod);
	return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值