hdu5106(组合数学)

来源:互联网 发布:网络位置是什么 编辑:程序博客网 时间:2024/04/29 12:49

题意:给一个二进制数R,长度不超过1000,问比R小并且1的个数为n的二进制数的和是多少。


解法:其实只需要枚举某个二进制数和R第一个1不同的位置就行了。因为如果R某个位置的1变成了0,那么以后01就随便取变成了组合数的问题。求和就预处理下1000内2的幂和前缀和了。我做时候复杂化,又求了小于等于R且1个数是n的二进制了。其实不用这一步了。


代码:

/******************************************************* @author:xiefubao*******************************************************/#pragma comment(linker, "/STACK:102400000,102400000")#include <iostream>#include <cstring>#include <cstdlib>#include <cstdio>#include <queue>#include <vector>#include <algorithm>#include <cmath>#include <map>#include <set>#include <stack>#include <string.h>//freopen ("in.txt" , "r" , stdin);using namespace std;#define eps 1e-8#define zero(_) (abs(_)<=eps)const double pi=acos(-1.0);typedef long long LL;const int Max=1010;const LL INF=1000000007 ;LL C[Max][Max];LL po[Max];LL sum[Max];char s[Max];int n;void init(){    for(int i=0; i<Max; i++)        for(int j=0; j<=i; j++)            C[i][j]= j==0?1:(C[i-1][j-1]+C[i-1][j])%INF;    po[0]=1;    sum[0]=1;    for(int i=1; i<Max; i++)    {        po[i]=po[i-1]*2%INF;        sum[i]=(sum[i-1]+po[i])%INF;    }}LL getans(bool f){    int have=0;    LL ans=0;    int len=strlen(s);    LL be=0;    for(int i=0; i<len; i++)    {        int sheng=len-1-i;        int ge=n-have-1;        if(s[i]=='1')        {            ans=(ans+(C[sheng-1][ge]*sum[sheng-1]%INF)%INF)%INF;            //cout<<"be: "<<be<<" "<<C[sheng+1][ge+1]<<endl;            //cout<<ans<<" ";            ans=(ans+be*C[sheng][ge+1]%INF)%INF;            //cout<<ans<<endl;            if(f)ans=(ans+po[len-i-1])%INF;            be=(be+po[len-i-1])%INF;            //cout<<ans<<endl;            have++;        }    }    return ans%INF;}LL solve(){    int len=strlen(s);    int m=0;    for(int i=0; i<len; i++)        if(s[i]=='1')            m++;    if(m<n)    {        int now=0;        int need=n-m+1;        int i;        for(i=len-1; i>=0; i--)        {            if(s[i]=='0')                now++;            if(now==need)                break;        }        for(; i>=0; i--)        {            if(s[i]=='1')            {                s[i]='0';                i++;                for(; i<len; i++)                {                    if(s[i]=='0')                    {                        need--;                        s[i]='1';                    }                    if(need==0)                        break;                }                int j=i+1;                i++;                for(;i<len;i++)                {                    if(s[i]=='1')                    {                        s[i]='0';                        s[j++]='1';                    }                }                break;            }        }    }    else if(n<m)    {        int need=m-n;        for(int i=len-1; i; i--)        {            if(s[i]=='1')                s[i]='0',need--;            if(need==0)                break;        }    }    int sad=0;    for(int i=0; i<len; i++)if(s[i]=='1')sad++;    if(sad!=n)        return 0;    //puts(s);    return getans(m!=n);}int main(){    init();    while(scanf("%d%s",&n,&s)==2)    {        if(n>strlen(s)||n==0)            cout<<"0"<<endl;        else            cout<<solve()<<endl;    }    return 0;}

0 0
原创粉丝点击