zoukankan      html  css  js  c++  java
  • 【2^k进制数】

    发现自己推得组合数好像不太一样

    先把这个复杂的柿子写一遍

    [sum_{i=2}^{left lfloorfrac{n}{k} ight floor}C_{2^k-1}^{i}+sum_{i=1}^{2^{n ext{ } ext{mod} ext{ }k}-1}C_{2^k-1-i}^{left lfloorfrac{n}{k} ight floor} ]

    感觉这个柿子非常蛇皮

    但是非常好求啊

    由于(2^k-1)非常小,最大仅仅是(511),所以我们没有什么必要预处理阶乘,我们可以直接用组合数递推的方式来做

    于是不需要打高精除或者高精乘了,一个高精加就够了

    于是做法就非常无脑了,重要的是这个柿子是怎么推出来的

    首先我们先考虑一个非常弱化的版本,就是(k|n)

    如果(k|n)的话,**那么这个长度为(n)的二进制数就能被恰好分成(n/k)个块,而且每一个块能选择的数都是(0)(2^k-1)(2^k)个数
    **

    我们发现(0)这个非常不好考虑,于是我们可以先忽略掉(0)

    所以现在有(n/k)个块,每个块内能填(2^k-1)种数

    那么就有(C_{2^k-1}^{n/k})种可能

    之后我们再来考虑(0)的情况,首先最高位(如果不是第二位的话)是可以填(0)的,而剩下的(n/k-1)个块我们仍旧按照之前的方式来填,于是就有(C_{2^k-1}^{n/k-1}),之后对于次高位还是可以填(0)(同时最高位也填(0)),那么还有(n/k-2)个块,于是就是(C_{2^k-1}^{n/k-2})

    以此类推,直到对于第三个的块,我们还是可以填将这个块以及之前所有的块都填(0),那么就还有(2)个块,于是就是(C_{2^k-1}^{2})

    而第二个块可是不能填(0)了,于是就没了

    所以对于(k|n)的时候,答案就是

    [sum_{i=2}^{n/k}C_{2^k-1}^{i} ]

    之后我们再来考虑一下(k)不整除(n)的情况

    这个样子的话一共会分成(left lfloorfrac{n}{k} ight floor+1)个块,(left lfloorfrac{n}{k} ight floor)个块内可以选择的数都是(0)(2^k-1)(2^k)个数,而最后一个不完整的块只有(n ext{ } ext{mod} ext{ }k)位,所以能选择的数只有(0)(2^{n ext{ } ext{mod} ext{ }k}-1)

    如果这个最高位选择填(0)那么退化成了(k|n)的情况,所以最高位填0的方案数为

    [sum_{i=2}^{left lfloorfrac{n}{k} ight floor}C_{2^k-1}^{i} ]

    之后最高位还有(1)(2^{n ext{ } ext{mod} ext{ }k}-1)这些数可以填,如果我们选择填(i)的话,那么剩下的块内就不能填比(i)小的数,于是剩下的每个块内能选择的就有(2^k-1-i)个数,所以方案数就是(C_{2^k-1-i}^{left lfloorfrac{n}{k} ight floor})

    所以最后的答案还应该加上

    [sum_{i=1}^{2^{n ext{ } ext{mod} ext{ }k}-1}C_{2^k-1-i}^{left lfloorfrac{n}{k} ight floor} ]

    代码

    #include<cstring>
    #include<string>
    #include<cstdio>
    #include<iostream>
    #define re register
    #define maxn 512
    using namespace std;
    string c[maxn][maxn];
    int n,k;
    int p,t;
    int res;
    int aa[201],bb[201],cc[201];
    inline string sum(string a,string b)
    {
        memset(aa,0,sizeof(aa));
        memset(bb,0,sizeof(bb));
        memset(cc,0,sizeof(cc));
        int lena=a.size();
        int lenb=b.size();
        for(re int i=0;i<lena;i++)
            aa[i+1]=a[lena-i-1]-48;
        for(re int i=0;i<lenb;i++)
            bb[i+1]=b[lenb-i-1]-48;
        int p=1;
        for(p=1;p<=max(lena,lenb)||cc[p];p++)
        {
            cc[p]+=aa[p]+bb[p];
            cc[p+1]+=cc[p]/10;
            cc[p]%=10;
        }
        string C="";
        for(re int i=p-1;i;i--)
            C+=char(cc[i]+48);
        return C;
    }
    int main()
    {
    	scanf("%d%d",&k,&n);
    	p=n/k;
    	res=n%k;
    	t=(1<<k);
    	c[0][0]="1";
    	for(re int i=1;i<=t-1;i++)
    		c[i][0]=c[i][i]="1";
    	for(re int i=1;i<t;i++)
    	for(re int j=1;j<i;j++)
    		c[i][j]=sum(c[i-1][j-1],c[i-1][j]);
    	string ans="0";
    	for(re int i=2;i<=p;i++)
    	{
    		if(i>t-1) break;
    		ans=sum(ans,c[t-1][i]);
    	}
    	int pp=(1<<res)-1;
    	for(re int i=1;i<=pp;i++)
    	{
    		if(p>t-1-i) break;
    		ans=sum(ans,c[t-1-i][p]);
    	}
    	cout<<ans<<endl;
    	return 0;
    }
    
  • 相关阅读:
    phpcurl使用
    系统常见问题
    java虚拟机CPU占用率过高排查方法
    oracle常用维护SQL
    PPT常用演示技能
    VS快捷键
    微软企业库缓存使用
    Oracle导sql的一个简便方法
    领域驱动设计
    sqluldr2
  • 原文地址:https://www.cnblogs.com/asuldb/p/10207756.html
Copyright © 2011-2022 走看看