【Codecraft-18 and Codeforces Round #458 (Div. 1 + Div. 2, combined) C】 Travelling Salesman and Special Numbers

【链接】 我是链接,点我呀:)
【题意】

在这里输入题意

【题解】

会发现。 进行一次操作过后。 得到的数字肯定是<=1000的 然后1000以下可以暴力做的。 则我们枚举第1步后得到的数字x是什么 反推初始数字。

可以写一个数位dp的。
即统计二进制数字y,满足y中1的个数为x然后y<=n
(一旦已经小于n了,则直接用组合数算方案就可以了

k=0和k=1要特殊处理一下

具体看代码

【代码】

#include <bits/stdc++.h>
#define ll long long
using namespace std;

const int N = 1e3;
const ll MOD = 1e9+7;

int k,a[N+10],n;
ll ans = 0,C[N+10][N+10];
string s;
vector<int> v;

int GetNext(int x){
    int y = 0;
    while (x){
        y+=(x&1);
        x>>=1;
    }
    return y;
}

void dfs(int pos,int rest,bool xiao){
    if (n-pos+1<rest) return;
    if (rest==0){
        ans = (ans+1)%MOD;
        return;
    }
    if (pos>n) return;

    if (xiao){
        ans = (ans + C[n-pos+1][rest])%MOD;
        return;
    }
    if (a[pos]==1){
        dfs(pos+1,rest-1,xiao);
        dfs(pos+1,rest,true);
    }else{
        if (xiao) dfs(pos+1,rest-1,xiao);
        dfs(pos+1,rest,xiao);
    }
}

int main(){
	#ifdef LOCAL_DEFINE
	    freopen("rush_in.txt", "r", stdin);
	#endif
	ios::sync_with_stdio(0),cin.tie(0);

	for (int i = 0;i <=N;i++)
        C[i][i] = C[i][0] = 1;
    for (int i = 1;i <= N;i++)
        for (int j = 1;j <= i-1;j++)
            C[i][j] = (C[i-1][j]+C[i-1][j-1])%MOD;

    cin >> s;
    cin >>k;

    for (int i = 0;i<(int) s.size();i++)
        a[i+1] = s[i]-'0';
    n = (int)s.size();

    if (k==0){
        cout <<1<<endl;
        return 0;
    }

    //what if n==1 k==0
    for (int i = 1;i <=N;i++){
        int x = i;
        int step = 0;
        while (x!=1){
            step++;
            x=GetNext(x);
        }
        if (step==(k-1)) {
            v.push_back(i);
        }
    }

    for (int i = 0;i<(int)v.size();i++){
        dfs(1,v[i],false);
    }
    if (k==1) {
        ans = (ans-1+MOD)%MOD;
    }
    cout << ans << endl;
	return 0;
}
原文地址:https://www.cnblogs.com/AWCXV/p/8323118.html