1. 程式人生 > >Codeforces Round #458 C Travelling Salesman and Special Numbers

Codeforces Round #458 C Travelling Salesman and Special Numbers

題意:給定一種reduce操作(將某數置成其二進位制表示下1的個數),某數reduce到1所需要的操作次數為其步長,給一個二進位制數,要求求出小於該數且步長為k的所有數的個數模1e9+7。

思路: 

注意到所有範圍內的數的二進位制表示下1的個數不會超過1000,所以所有數經一步操作後會落在1-1000範圍內,同理,再操作一次會

落到1-10的範圍,而1-10內步長最長的為7(步長為3),所以所有範圍內的數步長不會超過5。此外,步長為k的數的二進位制表示中1

的個數必然為一個步長為k-1的數。所以,要求1-2^1000中數的步長可以由1-1000中數的步長+1得到。

不妨先寫一個函式,它的功能為求出小於給定n的二進位制表示中1的個數為num的數的數量模1e9+7。

故對於給定的n和k,我們先求出1-1000內所有數的步長,對於給定的k,遍歷1-n.len,找到步長為k-1的數作為上述函式的輸入,累加

即可。

AC程式碼如下:

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

#define MOD 1000000007

string n;
int len;
int k;
int record[1006][1005];
int tttt[10] = {1,2,4,8,16,32,64,128,256,512};

void init()
{
    record[1005][1] = 0;
    record[1005][2] = 1;
    record[1005][3] = 2;
    record[1005][4] = 1;
    record[1005][5] = 2;
    record[1005][6] = 2;
    record[1005][7] = 3;
    record[1005][8] = 1;
    record[1005][9] = 2;
    record[1005][10] = 2;
    for(int i=11;i<=1000;++i)
    {
        int cnt = 0;
        int n = i;
        int j = 9;
        while(n<tttt[j]) j--;
        while(n)
        {
            while(n>=tttt[j])   n -= tttt[j],cnt++;
            j--;
        }
        record[1005][i] = record[1005][cnt]+1;
    }

    for(int i=1;i<=1000;++i)    record[i][0]=record[i][i]=1;
    for(int i=1;i<=1000;++i)
    {
        for(int j=1;j<i;++j)
            record[i][j] = (record[i-1][j]+record[i-1][j-1])%MOD;
    }
}

int ca(int num)
{
    if(num>len)     return 0;
    else if(num==1)     return len-1;
    int ans = 0;
    int cur = 1;
    for(int i=1;i<len;++i)
    {
        if(n[i]=='1')
        {
            int temp =record[len-i-1][num-cur];
            ans = (ans + record[len-i-1][num-cur])%MOD;
            cur++;
            if(cur==num)  {ans=(ans+1)%MOD; break;}
        }
    }
    for(int i=1;i<=len-num;++i)
    {
        ans = (ans+record[len-i-1][num-1])%MOD;
    }
    return ans;
}

int solve()
{
    if(k==0)    return 1;
    if(k>5)     return 0;
    int ans = 0;
    for(int i=1;i<=len;++i)
    {
        if(record[1005][i]==k-1)
            ans = (ans + ca(i))%MOD;
    }

    return ans;
}



int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    init();
   // for(int i=1;i<=1000;++i)    cout<<i<<" "<<record[0][i]<<endl;
    while(cin>>n>>k)
    {
        len = n.length();
        cout<<solve()<<endl;
    }

    return 0;
}