☰
一道难题【牛客tracker 每日一题】
2026/10/13 10:21:18 网站建设 项目流程

一道难题

时间限制:1 秒
空间限制:256M

网页链接

牛客tracker

牛客tracker & 每日一题,完成每日打卡,即可获得牛币。获得相应数量的牛币,能在【牛币兑换中心】,换取相应奖品!助力每日有题做,丰盈牛币日益多!


题目描述

给定一个数字n nn,求出1 − n 1 - n1−n中只由0 00或1 11组成的,且至少有三个1 11相连的数(不含前导零)有多少个。


输入描述

第一行一个整数n ( 1 ≤ n ≤ 10 23 ) n\ (1 \le n \le 10^{23})n(1≤n≤1023)。


输出描述

一个整数,表示满足条件的数的个数。


示例 1

输入:

2001

输出:

3

说明:1 − 2001 1 - 20011−2001中,满足条件的有:111 , 1110 , 1111 111,\ 1110,\ 1111111,1110,1111。


数据范围与提示

解题思路

解题思路

本题是数位 DP的经典应用。要求统计1 ∼ n 1 \sim n1∼n中,十进制表示仅由0和1组成,且至少包含连续三个1的数的个数。由于n nn最大可达10 23 10^{23}1023(最多 24 位),无法暴力枚举,需要按位进行动态规划。

1. 问题等价转化
2. 状态设计

定义dfs(p, c, tight, ok):

3. 状态转移
4. 最终答案

调用dfs(0, 0, 1, 0)即可得到1 ∼ n 1 \sim n1∼n中满足条件的数的个数。

5. 复杂度分析

总结

利用数位 DP 逐位构造只含0和1的数字,同时跟踪末尾连续1的个数和是否已出现过111。通过tight参数保证不超过n nn,允许前导零使得所有长度不超过L LL的数字都能被统一处理。该方法高效且代码简洁。

代码内容

#include<bits/stdc++.h>usingnamespacestd;#defineendl'\n'typedeflonglongll;typedefunsignedlonglongull;typedefvector<vector<ll>>vvt;typedefpair<ll,ll>pll;constll N=1e3+10;constll INF=1e18;constll M=1e6+10;constll mod=1e9+7;string S;ll f[25][3][2][2];lldfs(ll p,ll c,ll l,ll o){if(p==(ll)S.size())returno?1:0;ll lt=l;ll ot=o;if(f[p][c][lt][ot]!=-1)returnf[p][c][lt][ot];ll res=0;ll up=l?(S[p]-'0'):1;for(ll d=0;d<=up;d++){if(d>=2)continue;ll nl=l&&(d==up);ll nc;if(d==1)nc=c+1;elsenc=0;ll no=o||(nc>=3);if(nc>=3)nc=0;res+=dfs(p+1,nc,nl,no);}returnf[p][c][lt][ot]=res;}intmain(){ios::sync_with_stdio(0);cin.tie(0),cout.tie(0);cin>>S;memset(f,-1,sizeof(f));ll ans=dfs(0,0,1,0);cout<<ans<<endl;return0;}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询