杨辉三角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;
}