组合数学 模板

版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/86258258

杨辉三角p1632(二项式定理)

题目

描述 Description
杨辉三角是南宋数学家杨辉在《详解九章算法》(1261年)记载并保存了的一个三角形,故称杨辉三角。而在欧洲直到1623年以后,法国数学家帕斯卡在13岁时发现了“帕斯卡三角”。而帕斯卡三角与杨辉三角是一模一样的。
::点击图片在新窗口中打开::
杨辉三角表中的系数具有一定规律,每一行比上一行多一个数,每行除左右两个“一”外,每个数都是其“肩”(左上和右上)上两个数之和.
现在明明在学习杨辉三角的时候,他提出一个问题,如果给出杨辉三角和的行标和列标,能否得到那个元素的值。
例如: 第3行 第3列的元素值就为1,第7行第4列的元素就为20。
但是,第3行第5列是没有值的,对于这种情况我们要能够判断。
杨辉三角的系数是和二项式展开的系数存在一一对应关系。
输入格式 Input Format
第一行读入一个正整数n,表明往下为n行数据。(n<=30)
从第二行到第n+1行,每行两个正整数数(x和y),分别表示杨辉三角里元素的行标和列标(x,y<=30)
如果出现x>y,即出现杨辉三角没有值的情况,我们输出” Error!”(双引号内的内容)
输出格式 Output Format
n行数,与输入想对应行标和列标的 杨辉三角的元素值。
样例输入 Sample Input
4
3 3
7 4
5 9
4 4
样例输出 Sample Output
1
20
Error!
1
时间限制 Time Limitation
1s
注释 Hint
本题需要查询很多次,建议先把整个杨辉三角求出,在根据程序的查询输出值。
来源 Source
经典问题

代码

#include<bits/stdc++.h>
using namespace std;
int a[31][31];
int main()
{
	int n,x,y;
	cin>>n;
	a[1][1]=1;
	int t=0;
	for (int i=2;i<=30;i++)
		for (int j=1;j<=30;j++)
			a[i][j]=a[i-1][j]+a[i-1][j-1];
	for (int k=1;k<=n;k++)
	{
		cin>>x>>y;
		if (a[x][y]==0) cout<<"Error!"<<endl;
		else cout<<a[x][y]<<endl;
	}
	return 0;
}

康托展开

先放概念:
康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩。 康托展开的实质是计算当前排列在所有由小到大全排列中的顺序,因此是可逆的。
https://www.luogu.org/problemnew/show/P2524

#include<bits/stdc++.h>
using namespace std;
const int fac[]={1,1,2,6,24,120,720,5040,40320,362880};//阶乘 
inline int read()
{
	int f=1,num=0;
	char ch=getchar();
	while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); }
	while (isdigit(ch)) num=(num<<1)+(num<<3)+(ch^48), ch=getchar();
	return num*f;
}
char s[108];
int n;
inline int contor(char s[],int n)
{
	int ans=0;
	for (register int i=0;i<n;++i)
	{
		int smaller=0;
		for (register int j=i+1;j<n;++j)
			if (s[i]>s[j]) ++smaller;
		ans+=smaller*fac[n-i-1];
	}
	return ans+1;
}
int main()
{
	n=read();
	cin>>s; 
	printf("%d\n",contor(s,n));
	return 0;
}

Stirling

[第一类strling数]拆教室

http://acm.hdu.edu.cn/showproblem.php?pid=3625

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=110;
inline int read()
{
	int f=1,num=0;
	char ch=getchar();
	while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); }
	while (isdigit(ch)) num=(num<<1)+(num<<3)+(ch^48), ch=getchar();
	return num*f;
}
ll stirling[maxn][maxn],distribute[maxn];
inline void init()
{
	for (int i=1;i<=20;++i)//第一类Stirling数的递推公式
	{
		stirling[i][0]=0,stirling[i][i]=1;
		for (int j=1;j<i;++j)
        	stirling[i][j]=stirling[i-1][j-1]+(i-1)*stirling[i-1][j];
	}
	//求钥匙分布情况数
	distribute[1]=1;
	for (int i=2;i<=20;++i)
		distribute[i]=distribute[i-1]*i;
}
int main()
{
	int t=read();
	init();
	while (t--)
	{
    	int n=read(),k=read();
    	ll ans=0;
    	for (int i=1;i<=k;++i)
            ans+=stirling[n][i]-stirling[n-1][i-1];
    	printf("%.4lf\n",ans*1.0/distribute[n]);
   }
   return 0;
}

[第二类Stirling数]盒子与球

描述 Description
现有r个互不相同的盒子和n个互不相同的球,要将这n个球放入r个盒子中,且不允许有空盒子。问有多少种方法?
例如:有2个不同的盒子(分别编为1号和2号)和3个不同的球(分别编为1、2、3号),则有6种不同的方法:

1号盒子 1号球 1、2号球 1、3号球 2号球 2、3号球 3号球
2号盒子 2、3号球 3号球 2号球 1、3号球 1号球 1、2号球

输入格式 Input Format
两个整数,n和r,中间用空格分隔。(0≤n, r≤10)
输出格式 Output Format
一个整数,如题目描述
样例输入 Sample Input
3 2
样例输出 Sample Output
6
时间限制 Time Limitation
各个测试点1s
注释 Hint
第二类Stirling数

代码

#include<bits/stdc++.h>
#define up(i,a,b) for (register int i=a;i<=b;++i)
#define down(i,a,b) for (register int i=a;i>=b;--i)
using namespace std;
inline int read()
{
	int f=1,num=0;
	char ch=getchar();
	while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); }
	while (isdigit(ch)) num=(num<<1)+(num<<3)+(ch^48), ch=getchar();
	return num*f;
}
int work(int x,int y)
{
	if (y==1) return 1;
	else if (y==x) return 1;
	else return work(x-1,y-1)+y*work(x-1,y);
}
int main()
{
	int n=read(),r=read();
	if (n==1 || r==1)
	{
		puts("1");
		exit(0);
	}
	int d=work(n,r);
	up(i,1,r)
		d*=i;
	printf("%d\n",d);
	return 0;
}

卢卡斯定理

https://www.luogu.org/problemnew/show/P3807

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100010;
inline int read()
{
    int f=1,num=0;
    char ch=getchar();
    while (!isdigit(ch)) { if (ch=='-') f=-1; ch=getchar(); }
    while (isdigit(ch)) num=(num<<1)+(num<<3)+(ch^48), ch=getchar();
    return num*f;
}
ll a[maxn];int p;
ll power(ll x,int y)
{
    ll ans=1;
    while (y)
    {
    	if (y&1)
    		ans=ans*x%p;
    	x=x*x%p;
    	y>>=1;
    }
    return ans;
}
ll C(ll n,ll m)
{
    if(m>n) return 0;
    return a[n]*power(a[m],p-2)%p*power(a[n-m],p-2)%p;
}
ll Lucas(ll n,ll m)
{
    if(!m) return 1;
    return C(n%p,m%p)*Lucas(n/p,m/p)%p;
}
int main()
{
    int T=read();
    while(T--)
    {
        int n=read(),m=read();p=read();
        a[0]=1;
        for(int i=1;i<=p;++i)
            a[i]=(a[i-1]*i)%p;
        printf("%lld\n",Lucas(n+m,n));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/huashuimu2003/article/details/86258258