2118: 墨墨的等式
https://www.lydsy.com/JudgeOnline/problem.php?id=2118
分析:
最短路。
题意就是判断[L,R]内多少数,可以被许多个a1,a2,a3...构成。设最小的Mi = min{ai}。L,R<=1e12
直接枚举肯定超时,那么换个方法枚举。
考虑一个能构成的数b,它一定可以分解为$b = k imes M_i + r, r<M_i$。而且$b + M_i$也是可以构成的。所以我们可以找到最小的%Mi=r的数,比它大的%Mi=r的数可以直接算了。
考虑如何计算最小的,%Mi=r的数:建一张无向图,共Mi个点,u表示%Mi=u点。dis[u]为最小的%Mi=u的数。那么可以跑最短路处理处dis[u](即我们要求的)。
然后就可以直接计算了。可以计算出小于等于R的减去小于等于L-1的。
设$dis[r]=k imes Mi + r$,那么小于等于R的就是$(R-dis[r])/M_i+1$,就是k可以是多少。
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<cctype> 7 #include<set> 8 #include<vector> 9 #include<queue> 10 #include<map> 11 using namespace std; 12 typedef long long LL; 13 14 inline int read() { 15 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 16 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 17 } 18 19 const LL INF = 1e18; 20 int a[20], n, Mi = 1e9; 21 LL dis[500005]; 22 bool vis[500005]; 23 24 #define pa pair<LL,int> 25 #define mp(a,b) make_pair(a,b) 26 27 priority_queue< pa, vector< pa >, greater< pa > > q; 28 29 void Dijkstra() { 30 for (int i=0; i<Mi; ++i) 31 dis[i] = INF, vis[i] = false; 32 q.push(mp(dis[0] = 0, 0)); 33 while (!q.empty()) { 34 int u = q.top().second; q.pop(); 35 if (vis[u]) continue; 36 vis[u] = true; 37 for (int i=1; i<=n; ++i) { 38 int v = (u + a[i]) % Mi; 39 if (dis[v] > dis[u] + a[i]) { 40 dis[v] = dis[u] + a[i]; 41 q.push(mp(dis[v], v)); 42 } 43 } 44 } 45 } 46 LL Calc(int i,LL x) { 47 if (dis[i] > x) return 0; 48 x -= dis[i]; 49 return x / Mi + 1; 50 } 51 int main() { 52 LL L, R; 53 cin >> n >> L >> R; 54 for (int i=1; i<=n; ++i) cin >> a[i], Mi = min(Mi, a[i]); 55 Dijkstra(); 56 LL Ans = 0; 57 for (int i=0; i<Mi; ++i) 58 if (dis[i] <= R) 59 Ans += Calc(i, R) - Calc(i, L - 1); 60 cout << Ans; 61 return 0; 62 }