ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

2^k进制数

2020-11-24 12:02:41  阅读:224  来源: 互联网

标签:lfloor frac 进制 int Big rfloor len


题目描述

设 \(S\) 是长度为 \(w\) 的 \(01\) 串。从串的右边开始,每 \(k\) 个字符分成一段(最后不够 \(k\) 个字符的也分成一段),组成一个小于 \(2^k\) 的数。然后这 \(\left\lceil\frac{w}{k}\right\rceil\) 个数将组成一个序列。若这个序列除去前导零后的长度不小于 \(2\) 且序列里的数严格递增,那么 \(S\) 就是一个合法的串。求所有合法的串的个数。

解法

计数题。一开始就往组合方面想了。这个直觉似乎是对的。

先除去第一个数不看,即强制选 \(0\)(因为它可能不是 \(2^k\),比较特殊),那么对于后面的 \(\lfloor \frac{w}{k} \rfloor\) 个数,如果直接取的话,每个数都可以取 \(0\) ~ \(2^p-1\),要满足严格递增,实际上就是在这 \(2^p\) 个数里面选 \(\lfloor \frac{w}{k} \rfloor\) 个来组成序列,那么方案就是

\[\binom{2^p}{\lfloor \frac{w}{k} \rfloor} \]

这样对吗?你会发现这是错的。因为可以有前导零,而且前导零并不是单增的。这就提示我们将前导零抛开,分步计算。现枚举一个 \(i\) ,强制后 \(i\) 个数不为 \(0\),有 \(2^k-1\) 种,前面剩下的数全部是 \(0\),有 \(1\) 种,那么总方案数实际上是

\[\sum_{i=2}^{\lfloor \frac{w}{k} \rfloor} \binom{2^k-1}{i} \]

(序列长度大于等于 \(2\) ,\(i\) 要从 \(2\) 开始枚举)
现在将第一个数不为 \(0\) 的方案加进来,枚举 \(i\) 表示第一个数选什么,那么对于后面 \(\lfloor \frac{w}{k} \rfloor\) 个数,就在大于 \(i\) 的数里面选。方案就有

\[\sum_{i=1}^{2^{b \bmod k}} \binom{2^k-1-i}{\lfloor \frac{w}{k} \rfloor} \]

答案就是

\[\sum_{i=2}^{\lfloor \frac{w}{k} \rfloor} \binom{2^k-1}{i} + \sum_{i=1}^{2^{b \bmod k}} \binom{2^k-1-i}{\lfloor \frac{w}{k} \rfloor} \]

考虑怎么求这个东西,我们发现 \(k\) 是一个很小的数,而对于 \(n<m\) ,\(\binom{n}{m}=0\),所以只需要预处理出 \(n<2^9\) 以内的组合数,用公式直接递推即可。

Tips

推完式子之后发现要写高精,长度范围在 \(200\) 以内。然后写了高精加之后,直接交了,全部 \(MLE\)。一算空间 \(2^9\times 2^9\times 200\times 4\approx 200 MB\)。然后我就想这道题不能预处理,就开始写暴力求组合数(以及高精乘和高精除)。写到一半觉得不可能有这么麻烦,就去翻题解,发现某大佬用的 \(string\) 来存的高精数组。得到启发后,将 \(int\) 换成了 \(char\),空间直接减成 \(50MB\)。一发过了。

Code

(加了一些边界判定,感性理解即可)

#include<stdio.h>
#include<string.h>
#define N (1<<9)

int n,k;

inline int max(int x,int y){return x>y? x:y;}
struct Big{
    char num[201],len;
    Big(int x=0){memset(num,0,sizeof(num)); len=0; while(x) num[++len]=x%10,x/=10;}
    Big operator +(const Big x){
        Big c; int cur=0;
        c.len=max(x.len,len);
        for(int i=1;i<=c.len;i++){
            c.num[i]+=num[i]+x.num[i]+cur;
            cur=c.num[i]/10;
            c.num[i]%=10;
        }
        if(cur) c.num[++c.len]=cur;
        return c;
    }
    inline void print(){
        for(int i=len;i>=1;i--)
            printf("%d",num[i]);
    }
}C[N][N];

inline int min(int x,int y){return x<y? x:y;}
int main(){
    scanf("%d%d",&k,&n);
    for(int i=0;i<512;i++) C[i][0]=Big(1),C[i][i]=Big(1);
    for(int i=1;i<512;i++)
        for(int j=1;j<i;j++)
            C[i][j]=C[i-1][j]+C[i-1][j-1];
    if(k>=n) printf("0");
    else{
        Big ans=Big(0);
        int p=1<<k; int rg=min(n/k,p-1);
        for(int i=2;i<=rg;i++)
            ans=ans+C[p-1][i];
        if(n%k&&p-1>n/k){
            int p_=1<<(n%k);
            for(int i=1;i<p_&&p-i-1>=n/k;i++)
                ans=ans+C[p-i-1][n/k];
        }
        ans.print();
    }
}
// 3 7

标签:lfloor,frac,进制,int,Big,rfloor,len
来源: https://www.cnblogs.com/wwlwQWQ/p/14029481.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有