题目链接

分析:给定 \(h,x,y,z\),对于 \(k \in [1,h]\),有多少个 \(k\) 满足 \(ax+by+cz=k\)

同余最短路


分析:学了一下同余最短路

我们把原题中 \(h - 1\) 方便处理,然后可以按照 模 \(x\) 把楼层分为若干个剩余类。那么对于一个剩余类,假设我们可以到达的最低的楼层为 \(k\),那么该剩余类里面所有 \(\geq k\) 的楼层我们都可以到达。

然后 \(\forall i \in [0,x)\) ,连边 \((i,(i+y)\;mod\;x)\),边权为 \(y\),对于 \(z\) 同理,这样我们以 \(0\) 为起点跑一次最短路,就可以求出一个剩余类里面可以到达的最低楼层。

\(dis[i]\) 为剩余系 \(i\) 中可以到达的最低楼层,那么 \(ans=\sum_{i=0}^{x-1}\lfloor\frac{h-dis[i]}{x}\rfloor + 1\),注意特判无法到达某个剩余类的情况

为了优化,我们一般选择 \(x,y,z\) 中最小的来划分剩余类

#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100;
struct edge{int v,d;};
struct node{
    int u;
    ll h;
    bool operator < (const node &rhs)const{
        return h > rhs.h;
    }
};
vector<edge> G[maxn];
inline void addedge(int u,int v,int d){G[u].push_back(edge{v,d});}
ll h,x,y,z,dis[maxn],ans;
bool vis[maxn];
inline void dijkstra(int s){
    memset(dis,0x7f,sizeof(dis));
    dis[s] = 0;
    priority_queue<node> q;
    q.push(node{s,0});
    while(!q.empty()){
        int u = q.top().u;q.pop();
        if(vis[u])continue;
        vis[u] = 1;
        for(auto e : G[u]){
            if(dis[u] + e.d < dis[e.v]){
                dis[e.v] = dis[u] + e.d;
                q.push(node{e.v,dis[e.v]});
            }
        }
    }
}
int main(){
    cin >> h >> x >> y >> z;
    h--;
    for(int i = 0;i < x;i++)
        addedge(i,(i + y) % x,y),addedge(i,(i + z) % x,z);
    dijkstra(0);
    for(int i = 0;i < x;i++)
        if(dis[i] <= h)ans += (h - dis[i]) / x + 1;
    cout << ans << '\n';
    return 0;
}

相关文章:

  • 2021-07-01
  • 2022-12-23
  • 2021-07-13
  • 2022-01-09
  • 2022-12-23
  • 2020-02-21
  • 2021-12-28
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-01-26
  • 2021-08-11
  • 2021-08-25
  • 2021-09-26
相关资源
相似解决方案