[国家集训队]墨墨的等式
Solution
虽然还有1天就AFO了,但还是象征性地写篇题解吧。/kk
首先我们可以先变成求 \([0,r]\) 地合法方案数,简单容斥即可。然后我们可以发现,我们如果取出一个值 \(m\),那么我们如果在模 \(m\) 意义下可以取到 \(B\pmod m\),那么我们实际上也一定可以。
所以我们可以建图,\(i\to (i+a_j)\pmod m\) 连上一条权值为 \(a_j\) 的边,那么到点 \(i\) 的最短路实际上就是在模 \(m\) 意义下为 \(i\) 的最小可以取到的值,那么合法的 \(B\) 的个数就会有 \(\lfloor\frac{B-\text{dis}_i}{m}\rfloor+1\)。
用 SPFA 即可。\(m\) 取 \(a_i\) 中非零最小值即可。
Code
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define int long long
#define MAXM 6000005
#define MAXN 500005
template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}
int n,m,L,R,mn = 1e9,a[MAXN];
struct edge{
int v,w,nxt;
}e[MAXM];
int toop = 1,head[MAXN];
void link (int u,int v,int w){
e[++ toop] = edge {v,w,head[u]};
head[u] = toop;
}
bool vis[MAXN];int dis[MAXN];
void Spfa (int s){
queue <int> q;
memset (dis,0x3f,sizeof (dis)),memset (vis,0,sizeof (vis)),vis[s] = 1,dis[s] = 0,q.push (s);
while (!q.empty()){
int u = q.front();q.pop (),vis[u] = 0;
for (Int i = head[u];i;i = e[i].nxt){
int v = e[i].v,w = e[i].w;
if (dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
if (!vis[v]) vis[v] = 1,q.push (v);
}
}
}
}
int getit (int r){
int res = 0;
for (Int i = 0;i < mn;++ i) if (dis[i] <= r) res += (r - dis[i]) / mn + 1;
return res;
}
signed main (){
read (n,L,R);
for (Int i = 1,x;i <= n;++ i){
read (x);
if (x) a[++ m] = x,chkmin (mn,x);
}
for (Int i = 0;i < mn;++ i)
for (Int j = 1;j <= m;++ j)
if (a[j] ^ mn) link (i,(i + a[j]) % mn,a[j]);
Spfa (0),write (getit (R) - getit (L - 1)),putchar ('\n');
return 0;
}