题解 P2371 [国家集训队]墨墨的等式
RemiliaScar1et · · 题解
解析
P3403 跳楼机 升级版。
我们可以仿照那题的经典做法,使用同余最短路解决问题。
对于所有的
之后我们枚举所有的剩余类
for(int i=0;i<base;i++)
{
for(int j=1;j<=n;j++)
add(i,(i+a[i])%base,a[i]);
}
然后在这个图上跑最短路。
这样之后,我们跑出来的最短路数组
现在我们考虑如何计算
首先我们能够轻易计算出
显然的是区间满足条件的数是类型与有前缀和性质的。
所以我们只需要计算:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int> PII;
const int N=5e6+10;
int n;
ll l,r,base=1e9;
vector<ll> a;
int head[N],ver[N<<1],nxt[N<<1],tot=0;
ll edg[N<<1];
void add(int x,int y,ll z)
{
ver[++tot]=y; edg[tot]=z; nxt[tot]=head[x]; head[x]=tot;
}
bool vis[N];
ll f[N];
priority_queue<PII, vector<PII>,greater<PII> > q;
void dijkstra()
{
memset(f,0x42,sizeof f);
memset(vis,0,sizeof vis);
f[0]=0; q.push({0,0});
while(q.size())
{
int x=q.top().second;
q.pop();
if(vis[x]) continue;
vis[x]=1;
for(int i=head[x];i;i=nxt[i])
{
int y=ver[i];
if(f[y]>f[x]+edg[i])
{
f[y]=f[x]+edg[i];
q.push({f[y],y});
}
}
}
}
int main()
{
scanf("%d%lld%lld",&n,&l,&r);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
if(x) a.push_back((ll)x),base=min(base,(ll)x);
}
for(int i=0;i<base;i++)
{
for(int j=0;j<a.size();j++)
add(i,(i+a[j])%base,a[j]);
}
dijkstra();
ll ansl=0,ansr=0;
for(int i=0;i<base;i++)
{
if(r>=f[i]) ansr+=(r-f[i])/base+1LL;
if(l-1>=f[i]) ansl+=(l-1-f[i])/base+1LL;]);
}
printf("%lld",ansr-ansl);
return 0;
}