P2371 [国家集训队] 墨墨的等式
P2371 [国家集训队] 墨墨的等式
题目翻译:
题面已经比较简单,就没必要翻译了。
思路:
本题与 P3403 跳楼机 较像。可以先去体验此题。
同样可以运用同余最短路,我们假设最小的 \(a[i]\) 作为基准,构建同余最短路,求出所有除 \(a[i]\) 以外,其他数的最小的不同组合组合,即所有最小的其余数的组合使其模 \(a[i]\) 不同。这样只需要用同余最短路后得出的 \(dis[i]\) 就是余 \(i\) 的最小组合。让后根据计算得出有多少种加 \(a[i]\) 的方案,可以使最后处于 \([l,r]\) 中,统计答案。
实现:
将数组 \(a\)进行排序,找到最小的 \(a[i]\) 作为基准 \(x\)。然后枚举所有不同的余数 \(i\),和枚举其他 \(a[j]\) 进行同余最短路的连边,即:
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
if(a[i]==0){
i--;
n--;
}
}
sort(a+1,a+1+n);
for(int i=0;i<a[1];i++){
for(int j=2;j<=n;j++){
e[i].push_back({(i+a[j])%a[1],a[j]});
}
}
由于要考虑存在 \(a[i]=0\) 的情况,其不能作为基准,所以直接不统计他即可(否则会 \(Wrong\) \(subtast\))
让后跑一边 \(dijkstra\) 求出所有 \(dis[i]\)。那答案就是:
\[\sum_{i=0}^{x-1}(\lfloor \frac{r-dis[i]}{x} \rfloor+1)
\]
但由于是要求是区间 \([l,r]\) 间才合法,所以还要减去 \(l-1\) 的情况。
完整代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e5+10;
struct edge{
int v,w;
};
struct node{
int u,dis;
bool operator>(const node &x)const{return dis>x.dis;}
};
int a[N];
vector<edge>e[N];
priority_queue<node,vector<node>,greater<node>>q;
int dis[N],vis[N];
void dijkstra(){
memset(vis,0,sizeof(vis));
memset(dis,0x3f3f3f3f3f3f3f3f,sizeof(dis));
dis[0]=0;
q.push({0,0});
while(!q.empty()){
int u=q.top().u;
q.pop();
if(vis[u])continue;
vis[u]=1;
for(auto ed:e[u]){
int v=ed.v,w=ed.w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
q.push({v,dis[v]});
}
}
}
}
signed main(){
int n,l,r;
scanf("%lld%lld%lld",&n,&l,&r);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
if(a[i]==0){
i--;
n--;
}
}
sort(a+1,a+1+n);
for(int i=0;i<a[1];i++){
for(int j=2;j<=n;j++){
e[i].push_back({(i+a[j])%a[1],a[j]});
}
}
dijkstra();
int ans=0;
for(int i=0;i<a[1];i++){
if(dis[i]<=r){
ans+=(r-dis[i])/a[1]+1;
}
if(dis[i]<l){
ans-=(l-dis[i]-1)/a[1]+1;
}
}
printf("%lld",ans);
}
同余最短路讲解
本文作者:XichenOC
本文链接:https://www.cnblogs.com/XichenOC/p/18702903
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
分类:
标签:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步