1. 程式人生 > >[bzoj2118]墨墨的等式——同餘最短路

[bzoj2118]墨墨的等式——同餘最短路

題目大意:

墨墨突然對等式很感興趣,他正在研究a1x1+a2x2++anxn=Ba_1x_1+a_2x_2+…+a_nx_n=B存在非負整數解的條件 他要求你編寫一個程式,給定N,{an}N,\{a_n\}以及BB的取值範圍,求出有多少B可以使等式存在非負整數解。 N12,0ai5×105,1BminBmax1012N\leq12,0\leq a_i\leq 5\times 10^5,1\leq B_{min} \leq B_{max} \leq 10^{12}

思路:

題目中要求的是非負整數解,於是我們可以把每一個數看成一個物品,求所有物品可以組成的體積。 但是直接跑揹包顯然是接受不了的 考慮到最後的體積集合,我們把它按照a[1](也就是任意一個數)的剩餘類分類。 雖然可以組成的體積種類很多,但是按照剩餘類分類之後體積的種類就只有5e5種 於是我們只需要求出每一個剩餘類最小的體積就好了,每一個合法的體積一定可以表示成a[1]×x+ba[1]\times x+b

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define debug(x) cout<<#x<<"="<<x<<endl #define pii pair<ll,int> #define fi first #define se second #define mk make_pair typedef long long ll; using namespace std; void File(){ freopen("bzoj2118.in","r",stdin); freopen("bzoj2118.out","w",stdout); } template<
typename T>void read(T &_){ T __=0,mul=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-')mul=-1; ch=getchar(); } while(isdigit(ch))__=(__<<1)+(__<<3)+(ch^'0'),ch=getchar(); _=__*mul; } const int maxn=20; const int maxm=5e5+10; const int maxe=6e6+10; int n,a[maxn]; ll b0,b1,ans,w[maxe],dis[maxm]; int beg[maxm],to[maxe],las[maxe],cnte=1; void add(int u,int v,ll val){las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v; w[cnte]=val;} void init(){ read(n); read(b0); read(b1); REP(i,1,n)read(a[i]); REP(i,0,a[1]-1)REP(j,1,n) add(i,(i+a[j])%a[1],a[j]); } priority_queue< pii,vector<pii>,greater<pii> >qu; void Dijkstra(){ memset(dis,63,sizeof(dis)); dis[0]=0; qu.push(mk(0,0)); while(!qu.empty()){ ll d=qu.top().fi; int u=qu.top().se; qu.pop(); if(dis[u]!=d)continue; for(int i=beg[u];i;i=las[i]){ int v=to[i]; if(d+w[i]<dis[v]){ dis[v]=d+w[i]; qu.push(mk(dis[v],v)); } } } } void work(){ REP(i,0,a[1]-1){ ll val=dis[i]; if(val<b0)ans+=(b1-val)/a[1]-(b0-val-1)/a[1]; else if(val<=b1)ans+=(b1-val)/a[1]+1; } printf("%lld\n",ans); } int main(){ // File(); init(); Dijkstra(); work(); return 0; }