传送门
题意:
设 r 是个 (2^k) 进制数,并满足以下条件:
(1)r 至少是个 2 位的 (2^k) 进制数。
(2)作为 (2^k) 进制数,除最后一位外, r 的每一位严格小于它右边相邻的那一位。
(3)将 r 转换为 2 进制数 q 后,则 q 的总位数不超过 w 。
在这里,正整数 k ( 1 ≤ k ≤ 9 )和 w ( k < w ≤ 30000 )是事先给定的。
问:满足上述条件的不同的 r 共有多少个?
此题为NOIP2006第4题
解法:
此题官方正解是递推,我们用组合直接推其性质 跑的快多了
设(n=lfloorfrac{w}{k} floor)
则
当(k|w)时,
n则表示(2^k)进制数的位数,且每一位数都可以取0到(2^k-1)
否则
会多出一个最高位,且最高位取到的数只能是0到(2^{w mod k}-1)
但我们先考虑最高位为0的情况
-
则还剩下n位给我们填数
-
若每一位都要填上数,每个数又不能重复,还要严格按照小到大排序
-
易得用0到(2^k-1)的数 填n位数的情况有(C^n_{2^k-1})
-
但是也可以第n位数为0,第n-1位数为0,根据上述结论可以得到这两种分别有(C^{n-1}_{2^k-1} C^{n-2}_{2^k-1})种
-
又因为第2位数不能为0
-
可得最高位为0的情况下,可取的数有
-
(sum^n_{i=2}C_{2^k-1}^i)种
那么当最高位不为0时
-
我们可以枚举最高位的数(i=1)到(2^{w mod k}-1)
-
那么还剩数(2^k-i-1)供n个数选择
-
即最高位为(i)时有(C_{2^k-i-1}^n)种
-
得最高位不为0时有
-
(sum^{2^{w mod k} -1}_{i=1}C_{2^k-i-1}^n)种
则答案为
(sum^n_{i=2}C_{2^k-1}^i+sum^{2^{w mod k} -1}_{i=1}C_{2^k-i-1}^n)
代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<map>
#define inf 100000000
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dwn(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
typedef long long ll;
const int mod=1e4;
int k,n,times,p2;
struct node{
int arr[60],len;
node()
{
memset(arr,0,sizeof(arr));
len=0;
}
void print()
{
printf("%d",arr[len]);
dwn(i,len-1,0)
{
printf("%04d",arr[i]);
}
putchar('
');
}
}c[520],ans;
node operator +(node a,node b)
{
node c;c.len=max(a.len,b.len);int x=0;
rep(i,0,c.len)
{
c.arr[i]=a.arr[i]+b.arr[i]+x;
x=c.arr[i]/mod;
c.arr[i]%=mod;
}
if(x>0)
c.arr[++c.len]=x;
return c;
}
node operator *(node a,int b)
{
node c;c.len=a.len;ll x=0;
rep(i,0,c.len)
{
c.arr[i]=(1ll*a.arr[i]*b+x)%mod;
x=(1ll*a.arr[i]*b+x)/mod;
}
while(x>0)
{
c.arr[++c.len]=x%mod;
x/=mod;
}
return c;
}
node operator /(node a,int b)
{
node c;c.len=a.len;ll x=0;
dwn(i,c.len,0)
{
c.arr[i]=(a.arr[i]+x*mod)/b;
x=(a.arr[i]+x*mod)%b;
}
dwn(i,c.len,1)
{
if(c.arr[i]==0) c.len--;
else break;
}
return c;
}
int main()
{
scanf("%d%d",&k,&n);
p2=(1<<k)-1,times=(1<<(n%k))-1;
c[0].arr[0]=1;
rep(i,1,min(p2,n/k))
{
c[i]=c[i-1]*(p2-i+1)/i;
}
rep(i,2,min(p2,n/k))
{
ans=ans+c[i];
}
if(n/k<=p2)
{
c[p2]=c[n/k];
rep(i,1,times)
{
c[p2-i]=c[p2-i+1]*(p2-i+1-n/k)/(p2-i+1);
ans=ans+c[p2-i];
}
}
ans.print();
return 0;
}