Codeforces 914 C Travelling Salesman and Special Numbers

Discription

The Travelling Salesman spends a lot of time travelling so he tends to get bored. To pass time, he likes to perform operations on numbers. One such operation is to take a positive integer x and reduce it to the number of bits set to 1 in the binary representation of x. For example for number 13 it‘s true that 1310?=?11012, so it has 3 bits set and 13 will be reduced to 3 in one operation.

He calls a number special if the minimum number of operations to reduce it to 1 is k.

He wants to find out how many special numbers exist which are not greater than n. Please help the Travelling Salesman, as he is about to reach his destination!

Since the answer can be large, output it modulo 109?+?7.

Input

The first line contains integer n (1?≤?n?<?21000).

The second line contains integer k (0?≤?k?≤?1000).

Note that n is given in its binary representation without any leading zeros.

Output

Output a single integer — the number of special numbers not greater than n, modulo 109?+?7.

Example

Input

1102

Output

3

Input

1111110112

Output

169

Note

In the first sample, the three special numbers are 3, 5 and 6. They get reduced to 2 in one operation (since there are two set bits in each of 3, 5 and 6) and then to 1 in one more operation (since there is only one set bit in 2).

最简单的数位dp类型,多加一维0\1表示是否贴上界(当初自己想的方法没想到还挺靠谱,,,基本上用了的题都对了)。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<vector>
#define ll long long
#define maxn 1010
#define ha 1000000007
using namespace std;
char s[maxn];
int n,m,c[maxn];
int num[maxn],k,ans;
int f[maxn][maxn][2];
//f[i][j][0/1]表示前i位中和为j,且是否贴上界的方案数 

inline int add(int x,int y){
	x+=y;
	if(x>=ha) x-=ha;
	return x;
}

inline void init(){
	num[0]=0;
	for(int i=1;i<=1005;i++) num[i]=num[i^(i&-i)]+1;
	c[1]=0,c[0]=123456;
	for(int i=2;i<=1005;i++){
		c[i]=c[num[i]]+1;
		//c[i]<5,虽然可能并没有什么卵用
	}
}

inline void solve(){
	n=strlen(s+1);
	//一开始是贴上界的,因为之前的位都是0。
	f[0][0][1]=1;
	for(int i=1;i<=n;i++) if(s[i]==‘1‘){
	//这一位是1的话是不可能选的数1个数为0且贴上界
		f[i][0][0]=add(f[i-1][0][0],f[i-1][0][1]);
		f[i][0][1]=0;
		for(int j=1;j<=i;j++){
			//不贴上界可能是 这一位为0且之前是否贴上界任意 或者 这一位为1且之前不贴上界
			f[i][j][0]=add(add(f[i-1][j][0],f[i-1][j][1]),f[i-1][j-1][0]);
			//贴上界只能是之前贴上界且当前位是1
			f[i][j][1]=f[i-1][j-1][1];
		}
	}
	else{
		f[i][0][0]=f[i-1][0][0];
		f[i][0][1]=f[i-1][0][1];
		for(int j=1;j<=i;j++){
			//不贴上界的话只能 这一位为0且之前不贴上界 或者 这一位为1且之前不贴上界
			f[i][j][0]=add(f[i-1][j][0],f[i-1][j-1][0]);
			//之所以没有f[i-1][j-1][1]是因为这一位是1的话是不可能贴上界的
			f[i][j][1]=f[i-1][j][1];
		}
	}

	ans=0;
	for(int i=0;i<=n;i++) if(c[i]==k-1) ans=add(ans,add(f[n][i][0],f[n][i][1]));

//这样枚举<=n的数的1的个数会有一个漏洞,那就是1将会被算到k==1的里面去,所以要特判一下
	if(k==0) ans++;
	else if(k==1) ans--;
}

int main(){
	init();
	scanf("%s",s+1);
	scanf("%d",&k);
	solve();
	printf("%d\n",ans);
	return 0;
}

  

原文地址:https://www.cnblogs.com/JYYHH/p/8419456.html

时间: 2024-08-01 16:04:53

Codeforces 914 C Travelling Salesman and Special Numbers的相关文章

CF914C Travelling Salesman and Special Numbers

题目描述 对于一个正整数x,我们定义一次操作是将其变为它二进制下“1”的个数,比如我们知道1310?=11012 ,而1101有三个"1",所以对13进行一次操作就会将其变为3.显而易见的是,对于一个正整数,我们在进行若干次操作后,一定会将其变为1. 给定n和k,其中n是在二进制下被给出,求出所有不大于n且将其变为1的最小操作次数为k的数的个数对10^9+7取模的结果. 1<=n<21000, 0<=k<=10000 题解 因为n在二进制下长度最大为1000,所

hdu5402 Travelling Salesman Problem(棋盘染色+模拟)

题目: Travelling Salesman Problem Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 906    Accepted Submission(s): 331 Special Judge Problem Description Teacher Mai is in a maze with n rows and m c

HDOJ 5402 Travelling Salesman Problem 模拟

行数或列数为奇数就能够所有走完. 行数和列数都是偶数,能够选择空出一个(x+y)为奇数的点. 假设要空出一个(x+y)为偶数的点,则必须空出其它(x+y)为奇数的点 Travelling Salesman Problem Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 747    Accepted Submission(s): 272

多校9 1007 Travelling Salesman Problem

Travelling Salesman Problem Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 829    Accepted Submission(s): 182Special Judge Problem Description Teacher Mai is in a maze with n rows and m columns

HDU 5402 Travelling Salesman Problem (模拟 有规律)

Travelling Salesman Problem Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 568    Accepted Submission(s): 200 Special Judge Problem Description Teacher Mai is in a maze with n rows and m colum

HDU 5402 Travelling Salesman Problem (构造)(好题)

大致题意:n*m的非负数矩阵,从(1,1) 只能向四面走,一直走到(n,m)为终点,路径的权就是数的和,输出一条权值最大的路径方案 思路:由于这是非负数,要是有负数就是神题了,要是n,m中有一个是奇数,显然可以遍历,要是有一个偶数,可以画图发现,把图染成二分图后,(1,1)为黑色,总能有一种构造方式可以只绕过任何一个白色的点,然后再遍历其他点,而绕过黑色的点必然还要绕过两个白色点才能遍历全部点,这是画图发现的,所以找一个权值最小的白色点绕过就可以了, 题解给出了证明: 如果n,mn,m都为偶数,

构造 - HDU 5402 Travelling Salesman Problem

Travelling Salesman Problem Problem's Link: http://acm.hdu.edu.cn/showproblem.php?pid=5402 Mean: 现有一个n*m的迷宫,每一个格子都有一个非负整数,从迷宫的左上角(1,1)到迷宫的右下角(n,m),并且使得他走过的路径的整数之和最大,问最大和为多少以及他走的路径. analyse: 首先,因为每个格子都是非负整数,而且规定每个格子只能走一次,所以为了使和尽可能大,必定是走的格子数越多越好.这样我们就需

【HDOJ 5402】Travelling Salesman Problem

[HDOJ 5402]Travelling Salesman Problem 一开始以为是搜索 仔细画了画发现就一模拟 奇数行或奇数列的时候怎么走都能全走完 偶数行偶数列的时候就要挑了 . * . * . * * . * . * . . * . * . * * . * . * . 以4*6为例(如上图 星号可以保证不取其中一个可遍历完全图 点好的话就会连带一些星号 所以绕过星号中的最小值 是最佳遍历方式 输入的时候找到最小值并记录下行列 遍历到改行前以 右走到头 下 左走到头 下 右走到头这种方

构造 Codeforces Round #107 (Div. 2) B. Phone Numbers

题目传送门 1 /* 2 构造:结构体排个序,写的有些啰嗦,主要想用用流,少些了判断条件WA好几次:( 3 */ 4 #include <cstdio> 5 #include <algorithm> 6 #include <cstring> 7 #include <cmath> 8 #include <vector> 9 #include <map> 10 #include <iostream> 11 #include &