1. 程式人生 > >2118: 墨墨的等式

2118: 墨墨的等式

ret long space name 我們 tchar 分析 out ron

2118: 墨墨的等式

https://www.lydsy.com/JudgeOnline/problem.php?id=2118

分析:

  最短路。

  題意就是判斷[L,R]內多少數,可以被許多個a1,a2,a3...構成。設最小的Mi = min{ai}。

  直接枚舉肯定超時,那麽換個方法枚舉。

  考慮一個能構成的數b,它一定可以分解為$b = k \times 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 \times 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 }

2118: 墨墨的等式