BZOJ - 2118 墨墨的等式 (分析 + 最短路)

題目鏈接

題意:

給出每一個 aia_iBB 的取值範圍,讓你求這樣一個等式 a1x1+a2y2++anxn=Ba_1 * x_1+a_2 * y_2+…+a_n * x_n=B,有多少組非負整數解。

分析:

乍一看好像很難,無從下手。

那麼就百度一下(霧

首先,我們知道,對於一個可以求出來的 BB,那麼肯定會有 BB %\% aia_i = xx,那麼這樣子每一個

B+kaiB + k*a_i k=1,2...(k = 1,2...)

都是可以被構造出來的。

那麼,這樣我們就可以對於每一個 xx 找出最小可能的 BB,然後就可以統計答案了。

那麼找出最小可能的 BB 的過程其實就是一個最短路問題。

然後 aia_i 取多少呢,當然是最小非 0 的的那個,越小那麼 xx 就越少,當然其他的 aia_i 也是可以的。

在這裏我把 vv 作爲我選的最小那個 aia_i

dis[i]dis[i] 表示 (a1x1+a2y2++anxn)(a_1 * x_1+a_2 * y_2+…+a_n * x_n) %\% v=iv=i 的最小路徑 。

跑完之後統計答案就是對於每一個 tag>=dis[i]tag >= dis[i]

ansans +=(tagdis[i])/v+1+= (tag-dis[i])/v+1

+1+1dis[i]dis[i] 本身也可以作爲一個答案。

代碼:

#include <bits/stdc++.h>
#include <ext/rope>
using namespace __gnu_cxx;
using namespace std;
#define mst(a,b) memset(a,b,sizeof(a))
#define ALL(x) x.begin(),x.end()
#define pii pair<int,int>
#define eps 1e-6
#define debug(a) cout << #a": " << a << endl;
#define eularMod(a, b) a < b ? a : a % b + b
inline int lowbit(int x){ return x & -x; }
const int N = 5e5 + 10;
const int mod = (int) 123456789;
const int INF = 0x3f3f3f3f;
const long long LINF = (1LL << 62);
typedef long long LL;
typedef unsigned long long ULL;
const double PI = acos(-1.0);
 
LL dis[N];
int v[20];
bool vis[N];
queue<int> Q;
int n, MI = INF;
 
void spfa () {
    for (;!Q.empty();) Q.pop();
    Q.push(0);
 
    for (;!Q.empty();) {
        int u = Q.front();
        Q.pop();
 
        vis[u] = false;
 
        for (int i = 1; i <= n; i++) {
            int to = (u + v[i]) % MI;
 
            if (dis[to] > dis[u] + v[i]) {
                dis[to] = dis[u] + v[i];
                if (!vis[to]) {
                    vis[to] = true;
                    Q.push(to);
                }
            }
        }
 
    }
}
LL query (LL x) {
    LL ans = 0;
 
    for (int i = 0; i < MI; i++) {
        if (x >= dis[i]) ans += (x - dis[i]) / MI + 1;
    }
 
    return ans;
}
 
int main() {
#ifdef purple_bro
    freopen("in.txt", "r", stdin);
//    freopen("out.txt","w",stdout);
#endif
    LL L, R;
 
    scanf("%d%lld%lld", &n, &L, &R);
 
    for (int i = 1; i <= n; i++) {
        scanf("%d", &v[i]);
        if (v[i] == 0) {
            i--;
            n--;
            continue;
        }
        MI = min(MI, v[i]);
    }
 
    mst(dis, 0x3f);
 
    dis[0] = 0;
 
    spfa();
 
    printf("%lld\n", query(R) - query(L - 1));
 
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章