Codeforces914C Travelling Salesman and Special Numbers

题意:输入一个二进制数(1<<1000)和一个K,有这样一种变换,(1101)2->3==(11)2-->2==(10)1-->1,所以f(1101) = 3,问比这个二进制小的且f(bit) == k的数有几个

题解:这个二进制最多1000个1, 设dp[i][j]代表前i位小于这个二进制而且1的个数为j的个数,

那么bit[i] == 1:dp[i][j] = dp[i-1][j-1]+c[i-1][j];(c[i][j]为组合数)

bit[i] == 0:dp[i][j] = dp[i-1][j];

接下来就要找出走K次的数

假如一个数走一次,f(a) = b那么b<1000

所以枚举b,1到1000计算出所有走(k-1)次的数相加就是答案

注意这里要考虑k == 0和k == 1的情况...........

#include <bits/stdc++.h>
#define maxn 101000
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
ll k, a[maxn], dp[1010][1010], l, mod = 1e9+7, ans1[1010], cnt, C[1010][1010];
char s[1010];
ll  get(ll x) {
    ll  sum = 0;
    while(x) {
        if(x&1) ++sum;
        x >>= 1;
    }
    return sum;
}
ll c(ll a,ll b){
    if(a<b) return 0;
    else return C[a][b];
}
int main(){
    scanf("%s", s);
    l = strlen(s);
    cin>>k;
    C[1][0] = C[1][1] = 1;
    for (int i = 2; i < 1010; i++){
        C[i][0] = 1;
        for (int j = 1; j < 1010; j++)
            C[i][j] = (C[i - 1][j] + C[i - 1][j - 1])%mod;
    }
    for(ll i=l-1;i>=0;i--) a[l-i] = s[i]-'0';
    if(a[1]) dp[1][1] = 1, dp[1][0] = 1;
    else dp[1][1] = 0, dp[1][0] = 1;
    for(ll i=2;i<=l;i++){
        dp[i][0] = 1;
        for(ll j=1;j<=l;j++){
            if(a[i]) dp[i][j] = (dp[i-1][j-1]+c(i-1, j))%mod;
            else dp[i][j] = dp[i-1][j]%mod;
        }
    }
    ll ans = 0;
    for(ll i=1;i<=1000;i++)
    {
        ll tmp = get(i);
        if(i==1) ans1[i] = 0;
        else  ans1[i] = ans1[tmp]+1;
        if(ans1[i]==k-1)
             ans = (ans+dp[l][i]) % mod;
    }
    if(k == 0) ans = 1;
    if(k == 1) ans = dp[l][1]-1;
    cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/Noevon/p/8327735.html