题意:给定h,x,y,z,求由x,y,z组成的数中有多少个小于等于h。
解:学习同余最短路的例题。由于h太大(h<=(1<<63)-1),考虑找规律。首先xyz中有任何一个为1答案为h。否则,将xyz能组成的数按照模x同余分类,于是现在只需要考虑y和z。为了和模运算一致,将h减一,求0~h-1中答案的个数。
用一个例子来说明:h=46, x=4,y=7,z=9
x的剩余系: 0 1 2 3
模x同余的最小数(di): 0 9 14 7
将h按照每x个数分一组,将 x的倍数+模x同余的最小数 填入:
如此计算一下,就有了oiwiki上的那个式子:
代码:

#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 300005 #define inf (1ull<<63)-1 #define int long long ll h,x,y,z; struct edge{ int u,v,w; int nxt; }e[maxx]; int head[maxx]={0},cnt=0; void add(int u,int v,int w){ e[++cnt].u=u; e[cnt].v=v; e[cnt].w=w; e[cnt].nxt=head[u]; head[u]=cnt; } ll dis[maxx]; int vis[maxx]={0}; void dijk(){ for(int i=0;i<x;i++) dis[i]=inf; dis[0]=0; priority_queue<pair<int,int> > q; q.push(make_pair(0,0)); while(!q.empty()){ int now=q.top().second; q.pop(); if(vis[now]) continue; vis[now]=1; for(int i=head[now];i;i=e[i].nxt){ int to=e[i].v; ll f=e[i].w+dis[now]; if(f<dis[to]){ dis[to]=f; q.push(make_pair(-dis[to],to)); } } } } signed main(){ scanf("%lld%lld%lld%lld",&h,&x,&y,&z); if(x==1||y==1||z==1){ printf("%lld\n",h); return 0; } for(int i=0;i<x;i++){ add(i,(i+y)%x,y); add(i,(i+z)%x,z); } dijk(); h--; ll ans=0; for(int i=0;i<x;i++){ if(h>=dis[i]) ans+=(h-dis[i])/x+1; } printf("%lld\n",ans); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
2022-10-29 Codeforces Round #831 (Div. 1 + Div. 2)