2^k进制数

传送门

题意:

设 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=\lfloor\frac{w}{k}\rfloor\)

\(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('\n');
    }
}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;
}

转载于:https://www.cnblogs.com/MYsBlogs/p/10910981.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值