CodeForces - 914C Travelling Salesman and Special Numbers
Posted on 2022-11-04 19:06 Capterlliar 阅读(25) 评论(0) 编辑 收藏 举报题意:给出一个二进制数a,每次操作将当前数变成其二进制下1的个数,若干次操作后可以将其变为1.给定k,求不大于a的数中,经过k次操作能变成1的数的数量。
解:观察一下这个操作,可以求出1000以内的数变成1的次数,设其为cnt[i]。对于1000以外的数,可以在一次操作后变到1000以内。枚举i,如果cnt[i]+1=k,那就说明二进制下拥有i个1的数,能在k次操作后变成1.接下来问题变成了有多少小于等于a的,二进制下有i个1的数。进行一些数位dp。
代码:

#include <bits/stdc++.h> using namespace std; #define maxx 100005 #define maxn 25 #define maxm 205 #define ll long long #define inf 1000000009 #define mod 1000000007 char a[1005]; int len; ll dp[1005][1005][2]={0}; int cnt[1005]={0}; int k; ll dfs(ll pos,ll kk,ll limit){ if(pos==len+1) { return kk==0; } if(kk<0) return 0; if(!limit&&dp[pos][kk][limit]!=-1) return dp[pos][kk][limit]; ll ret=0; ll res=limit?a[pos]-'0':1; for(int i=0;i<=res;i++){ ret=(ret+dfs(pos+1,kk-i,limit&&(i==a[pos]-'0')))%mod; } return !limit?dp[pos][kk][limit]=ret:ret; } signed main() { // int T; // scanf("%d",&T); // while(T--) {; // // } memset(dp,-1,sizeof dp); scanf("%s",a+1); scanf("%d",&k); if(k==0){ printf("1\n"); return 0; } len=strlen(a+1); ll ans=0; for(int i=1;i<=1000;i++){ if(i>1) { bitset<1005> b = i; cnt[i] = cnt[b.count()] + 1; } if(cnt[i]==k-1) { ans = (ans + dfs(1, i, 1)) % mod; } } if(k==1) ans--; printf("%lld\n",ans); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?