P2371 [国家集训队]墨墨的等式
zzr8178541919 · · 题解
考察的是『同余最短路』,很巧妙的一种处理方法。这里说一下自己的理解。
题意看上去很简单,但感觉无从下手,所以我们要一层一层地分析。
1.首先求区间
2.观察数据范围:发现
3.我们先给
4.进一步分析:确定了一个
5.感觉找到能够表示出的最小的%
6.总结:同余最短路是一种非常神奇的技巧,并可以在一些题目中得到完美的展现。实际上,我认为它是从
#include<bits/stdc++.h>
#define int long long
#define reg register
using namespace std;
const int maxn=1e6+5;
const int mod=31011;
const int INF=2e16;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
int n,l,r,a[maxn],k,vis[maxn],dist[maxn];
queue<int> q;
int Work(int x)
{
int res=0;
for(reg int i=0;i<k;i++)
{
if(dist[i]!=INF)
{
int wns=max((x-i)/k+1-dist[i],(int)0);
res+=wns;
}
}
return res;
}
signed main()
{
n=read();
l=read(),r=read();
for(reg int i=1;i<=n;i++)
{
a[i]=read();
}
sort(a+1,a+1+n);
k=a[1];
for(reg int i=0;i<=k;i++)
dist[i]=2e16;
dist[0]=0;
vis[0]=1;
q.push(0);
while(!q.empty())
{
int x=q.front();
q.pop();
vis[x]=0;
for(reg int i=1;i<=n;++i)
{
int t=(x+a[i])%k;
if(dist[t]>dist[x]+a[i])
{
dist[t]=dist[x]+a[i];
if(vis[t]==0)
{
vis[t]=1;
q.push(t);
}
}
}
}
for(reg int i=0;i<k;i++)
{
if(dist[i]!=INF)
{
dist[i]=(dist[i]-i)/k;
}
}
printf("%lld\n",Work(r)-Work(l-1));
return 0;
}