博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Codecraft-18 and Codeforces Round #458: C. Travelling Salesman and Sp(组合数)
阅读量:2143 次
发布时间:2019-04-30

本文共 1150 字,大约阅读时间需要 3 分钟。

对于数字x,令F[x] = x二进制中1的个数

输入两个数字n(输入为二进制)和k,问有多少个满足①<=n;②刚好进行k次F[]计算后变为1

思路:

显然n<=2^1000但是第一次F[]计算之后一定会变成一个<=1000的数

先预处理1到1000每个数要变几次,然后对于刚好变k-1次的数x就相当于求出有多少个数满足

①<=n;②二进制刚好有x个1

这可以用数位DP或者组合数学解决

大概就是如果当前位是1的话把它变成0后面所有数字都可以01任选了,具体看代码

最后对于每个合法的x算出来的情况数全部加在一起就是答案

不过这样有两个坑,一个是k=0是答案一定为1,第二个是k=1时注意计算出的答案要-1

#include
#include
#define LL long long#define mod 1000000007int a[1005];LL C[1005][1005];char str[1005];int Jud(int x){ int now, sum = 0; while(x>1) { sum++; now = 0; while(x) { if(x%2==1) now++; x /= 2; } x = now; } return sum;}LL Sech(int x){ LL sum = 0; int i, n, cnt = 0; n = strlen(str+1); for(i=1;i<=n;i++) { if(str[i]=='1') { if(cnt<=x) sum = (sum+C[n-i][x-cnt])%mod; cnt++; } } if(cnt==x) sum = (sum+1)%mod; return sum;}int main(void){ LL ans; int i, j, k; for(i=1;i<=1000;i++) a[i] = Jud(i); C[0][0] = 1; for(i=1;i<=1000;i++) { C[i][0] = 1; for(j=1;j<=i;j++) C[i][j] = (C[i-1][j-1]+C[i-1][j])%mod; } scanf("%s%d", str+1, &k); if(k==0) { printf("1\n"); return 0; } ans = 0; for(i=1;i<=1000;i++) { if(a[i]==k-1) ans = (ans+Sech(i))%mod; } if(k==1) ans--; printf("%I64d\n", ans); return 0;}

你可能感兴趣的文章
Oracle PL/SQL语言初级教程之异常处理
查看>>
Oracle PL/SQL语言初级教程之游标
查看>>
Oracle PL/SQL语言初级教程之操作和控制语言
查看>>
Oracle PL/SQL语言初级教程之过程和函数
查看>>
Oracle PL/SQL语言初级教程之表和视图
查看>>
Oracle PL/SQL语言初级教程之完整性约束
查看>>
PL/SQL学习笔记
查看>>
如何分析SQL语句
查看>>
结构化查询语言(SQL)原理
查看>>
SQL教程之嵌套SELECT语句
查看>>
几个简单的SQL例子
查看>>
日本語の記号の読み方
查看>>
计算机英语编程中一些单词
查看>>
JavaScript 经典例子
查看>>
判断数据的JS代码
查看>>
js按键事件说明
查看>>
AJAX 初次体验!推荐刚学看这个满好的!
查看>>
AJAX 设计制作 在公司弄的 非得要做出这个养的 真晕!
查看>>
Linux 查看文件大小
查看>>
Java并发编程:线程池的使用
查看>>