[BZOJ 2118] 墨墨的等式

[题目链接]

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

[算法]

         首先找出Min{Ai} 

         对于0 - Min{Ai} - 1分别建一个点 , 分别表示一个同余类

         若(i + Aj) % Min{Ai} = k , 则i向k连一条权值为Aj的边

         从0号点开始单源最短路 , 那么就得到了模Min{Ai}为任意数的最小值 

         计算较为简单 , 不再赘述

         时间复杂度 : O(Min{Ai}logMin{Ai}) (需要使用高效的Dijkstra + 堆优化算法)

[代码]

        

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 13;
const int MAXA = 5e5 + 10;
typedef long long LL;
const LL inf = 1e18;

struct edge
{
        int to , w , nxt;
} e[MAXN * MAXA];

int n , mn , tot;
LL Bmin , Bmax;
int a[MAXN] , head[MAXA];
bool visited[MAXA];
LL dist[MAXA];
priority_queue< pair<LL , int> , vector< pair<LL , int> > , greater< pair<LL , int> > > q; 

template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); }
template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); }
template <typename T> inline void read(T &x)
{
    T f = 1; x = 0;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
    x *= f;
}
inline void addedge(int u , int v , int w)
{
        ++tot;
        e[tot] = (edge){v , w , head[u]};
        head[u] = tot;
}
inline LL calc(LL x , LL y , LL z)
{
        LL ret = x / y;
        if (x % y >= z && x >= 1) ++ret;
        return ret;        
}

int main()
{
        
        read(n); read(Bmin); read(Bmax);
        for (int i = 1; i <= n; i++) read(a[i]);
        mn = a[1];
        for (int i = 2; i <= n; i++)
                if (a[i] < mn) mn = a[i];
        for (int i = 0; i < mn; i++) 
        {
                for (int j = 1; j <= n; j++)
                {
                        addedge(i , (i + a[j]) % mn , a[j]);        
                }        
        }
        for (int i = 0; i < mn; i++) dist[i] = inf;
        dist[0] = 0;
        q.push(make_pair(0 , 0));
        while (!q.empty())
        {
                int cur = q.top().second;
                q.pop();
                if (visited[cur]) continue;
                visited[cur] = true;
                for (int i = head[cur]; i; i = e[i].nxt)
                {
                        int v = e[i].to , w = e[i].w;
                        if (dist[cur] + w < dist[v])
                        {
                                dist[v] = dist[cur] + w;
                                q.push(make_pair(dist[v] , v));
                        }     
                }        
        }
        LL ans = 0;
        for (int i = 0; i < mn; i++)
        {
                LL l = max(dist[i] , Bmin) , r = Bmax;
                if (l > r) continue;
                ans += calc(r , mn , i) - calc(l - 1 , mn , i);    
        }
        printf("%lld\n" , ans);
        
        return 0;
    
}

 

posted @ 2018-11-03 20:05  evenbao  阅读(146)  评论(0编辑  收藏  举报