poj 1173 具有重复的组合和容斥原理
2010-08-12 00:04
204 查看
题目描述
计算BC(n,k,m),就是X1+X2+...+Xk=n,其中1<=Xi<=m,有多少个解?这些解顺序排列,输入一个排列,计算它是第几个?
详见http://acm.pku.edu.cn/JudgeOnline/problem?id=1173。
如BC(7,4,2),有16个解
0:1000100|8:1100100
1:1000110|9:1100110
2:1001000|10:1101000
3:1001100|11:1101100
4:1001110|12:1101110
5:1011000|13:1110010
6:1011100|14:1110100
7:1100010|15:1110110
然后输入
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<float.h>
usingnamespacestd;
#defineM104
typedefunsigned__int64UINT64;
intnum;
intg_n,g_k,g_m;
intinput[M][36];
intg_number[36];
intg_divider[36];
UINT64Combination(intn,intk)
{ //stillworkwhenn==k,reurn1
k=min(k,n-k);
for(inti=0;i<=k;i++)
{
g_number[i]=n-i;
g_divider[i]=i;
}
for(inti=2;i<=k;i++)
{
for(intj=0;j<k;j++)
{
if(g_number[j]%i==0){
g_number[j]/=i;
g_divider[i]=1;
break;
}
}
}
UINT64nRes=1;
for(inti=0;i<k;i++){
nRes*=g_number[i];
}
for(inti=2;i<=k;i++){
nRes/=g_divider[i];
}
returnnRes;
}
intFunc(intn,intk,intm)
{
n=n-k; //Xi=Yi+1
UINT64nRes=Combination(n+k-1,k-1);
intnSign=-1;
intnTmp;
for(inti=1;i<=k;i++)
{
nTmp=n-i*m;
if(n-i*m<0)
break;
nRes+=nSign*Combination(k,i)*Combination(nTmp+k-1,k-1);
nSign*=-1;
}
return(int)nRes;
}
intGetMinOnes(intnHandled,intkLeft)
{
returnmax(g_n-nHandled-(kLeft)*g_m,1);
}
intGetMaxZeros(intnHandled,intkLeft)
{
returnmin(g_n-nHandled-(kLeft),g_m);
}
intGetSequence(intnth)
{
intnLen;
intidx=0;
intnRes=0;
intnHandled=0;
inti;
for(i=1;i<=g_k-2;i++)
{
//odd
if(i%2==1){
nLen=0;
while(input[nth][idx++]!=0)
nLen++;
idx--;
for(intj=GetMinOnes(nHandled,g_k-i);j<=nLen-1;j++)
{
nRes+=Func(g_n-nHandled-j,g_k-i,g_m);
}
nHandled+=nLen;
}
//even
else{
nLen=0;
while(input[nth][idx++]!=1)
nLen++;
idx--;
for(intj=GetMaxZeros(nHandled,g_k-i);j>nLen;j--)
{
nRes+=Func(g_n-nHandled-j,g_k-i,g_m);
}
nHandled+=nLen;
}
}
//odd
if(i%2==1){
nLen=0;
while(input[nth][idx++]!=0)
nLen++;
nRes+=nLen-GetMinOnes(nHandled,g_k-i)+1;
}
//even
else{
nLen=0;
while(input[nth][idx++]!=1)
nLen++;
nRes+=GetMaxZeros(nHandled,g_k-i)-nLen+1;
}
returnnRes-1;
}
intmain()
{
//freopen("ReadMe.txt","r",stdin);
scanf("%d%d%d",&g_n,&g_k,&g_m);
scanf("%d",&num);
charbuf[36];
for(inti=0;i<num;i++)
{
scanf("%s",buf);
for(intj=0;j<g_n;j++){
input[i][j]=buf[j]-'0';
}
}
printf("%d/n",Func(g_n,g_k,g_m));
for(inti=0;i<num;i++)
{
printf("%d/n",GetSequence(i));
}
return0;
}[/code]
计算BC(n,k,m),就是X1+X2+...+Xk=n,其中1<=Xi<=m,有多少个解?这些解顺序排列,输入一个排列,计算它是第几个?
详见
如BC(7,4,2),有16个解
0:1000100|8:1100100
1:1000110|9:1100110
2:1001000|10:1101000
3:1001100|11:1101100
4:1001110|12:1101110
5:1011000|13:1110010
6:1011100|14:1110100
7:1100010|15:1110110
然后输入
743 5 1001110 1110110 1001100 1001110 1000100
输出
16 4 15 3 4 0
题目分析
IOI的题,做的我好爽呀。很多解题报告用观察的方法,我是通过组合数学分析的,也算是另一个思路吧。而且我相信从数学原理分析问题, 分析的更透彻,对本质把握的更好一些。 首先具有重复的组合数。若从k种物品中选出n个物品,其中每种物品可以原则无限多个,成为具有重复的组合数, 这个组合数等于C(n+k-1,k-1). 这个题等价于简单的数学表达是X1+X2+...+Xk=n,其中Xi>=0,有多少个解. 证明:把n个物品排成一排,用k-1个栏杆对它们进行划分,如下图所示 。。。|。。。|。。。 。||。。。。。。。。 这里n=9,k=3,第一个划分对应3+3+3=9;第二个划分对应1+0+8=9.划分和解是一一对应。 划分有C(n+k-1,k-1)种,所以解有C(n+k-1,k-1)种。 其次,容斥原理。集合A1不具有性质P1,集合A2不具有性质P2,...,那么不具有性质P1和P2...的集合中的元素的个数满足... 原谅我懒得把这个公式打出来,如果你想知道,网上随便就搜出来了。 那么回到本题,X1+X2+...+Xk=n,其中1<=Xi<=m的解的个数怎么计算呢?(1) 首先用Xi=Yi+1代替上式,得到Y1+Y2+...+Yk=n-k,其中0<=Yi<=m-1. 现在考虑式子Z1+Z2+...+Zk=n-k,其中Z0>=m;Zi>=0(i!=1)(2) 用A1表示解中不具有0<=Z1<=m-1的性质,但是其它解可以任取非负值,那么就是(2)的解。 要解(2)式,用Z1=W1+m代替,则W1可取任意值,这转化为可以求解的问题。 (2)式可以计算了,根据容斥原理就可以解(1)式。 至于排序的问题,观察观察就出来了,详情就看代码吧。
代码
相关文章推荐
- (字符串的模式模式匹配4.7.9)POJ 1782 Run Length Encoding(具有重复字符的字符串的处理方式)
- POJ 1091 跳蚤 [容斥原理]【组合数学】
- poj 1091 跳蚤(组合数学-容斥原理)这题要求的数据范围根本就是胡说八道!
- poj 1959 Darts 允许重复组合
- 剑指Offer28字符串的排列(递归和非递归实现)扩展有重复元素的排列,字符串的组合种类
- for循环的小练习之6个不重复数字的所有组合输出
- POJ 1850 Code 组合数学
- POJ 1084 Square Destroyer【Dancing Links重复覆盖】
- POJ 1850 组合编号
- Leetcode Subsets II 有重复元素的组合
- javascript算法题 求任意一个1-9位不重复的N位数在该组合中的大小排列序号
- uva 10325 The Lottery(组合数学-容斥原理)
- 递归求排列和组合(无重复和有重复)
- (组合数学3.1.1.1)POJ 1146 ID Codes(字典序法)
- POJ 3693 Maximum repetition substring (后缀数组+RMQ 求重复最多的连续子串)
- poj 1146 ID Codes (字符串处理 生成排列组合 生成当前串的下一个字典序排列 【*模板】 )
- POJ1150he Last Non-zero Digit(组合)
- javascript算法题 求任意一个1-9位不重复的N位数在该组合中的大小排列序号
- POJ 1091 跳蚤 数论-容斥原理、扩展欧几里得
- [ACM] poj 2249 Binomial Showdown (排列组合公式优化)