[2019.2.28]BZOJ2118 墨墨的等式
阿新 • • 發佈:2019-03-17
min floor 取值 ans bit 如果 -a esp can 到節點\((i+a_j)mod\ m\)有一條權值為\(a_j\)的單向邊。那麽\(d_i\)就是節點0到節點\(i\)的最短路。
我們設最小的系數為\(m\)。
那麽如果\(B=im+j\)(\(i,j\)為非負整數,\(j<m\))有整數解,那麽\(B=(i+k)m+j\)(\(k\)為正整數)也有整數解。我們只需要把\(B=im+j\)的整數解中系數\(m\)對應的未知數加\(k\)就好了。
所以我們記\(d_i\)表示\(B\)在\(mod\ m\)意義下同余\(i\),並且這個\(B\)有解的最小的\(B\)。
顯然\(d_0=0\)。
以及我們可以用\(d_i+a_j\)更新\(d_{(i+a_j)mod\ m}\)。
那麽可以理解為對於任意\(0\le i<m\)和\(1\le j\le n\),節點\(i\)
所以我們之所以選擇最小的系數作為\(m\),是為了減少狀態數。
跑一遍玄學的SPFA就能夠處理出\(d\)了。
那麽在\(mod\ m\)意義下和\(i\)同余且小於等於\(x\)的合法的\(B\)的取值數量為\(\lfloor\frac{x-d_i+m}{m}\rfloor\)。
於是我們設\(0\le B\le x\)時,使得方程有非負整數解的\(B\)取值的數量為\(ans(x)\),則\(ans(x)=\sum_{i=0}^{m-1}\lfloor\frac{max(x-d_i+m,0)}{m}\rfloor\)
題目所求即為\(ans(BMax)-ans(BMin-1)\)。
code:
#include<bits/stdc++.h> using namespace std; const long long INF=1e13; struct edge{ int t,v,nxt; }e[6000010]; int n,a[15],mn=1e9,cnt,be[500010],t,vis[500010]; long long bl,br,dis[500010],tot; queue<int>q; void add(int x,int y,int val){ e[++cnt].t=y,e[cnt].v=val,e[cnt].nxt=be[x],be[x]=cnt; } void SPFA(){ for(int i=1;i<mn;++i)dis[i]=INF; q.push(0); while(!q.empty()){ t=q.front(),q.pop(),vis[t]=0; for(int i=be[t];i;i=e[i].nxt)dis[e[i].t]>dis[t]+e[i].v?dis[e[i].t]=dis[t]+e[i].v,(!vis[e[i].t]?q.push(e[i].t),vis[e[i].t]=1:0):0; } } long long ANS(long long x){ tot=0; for(int i=0;i<mn;++i)tot+=max(0ll,x-dis[i]+mn)/mn; return tot; } int main(){ scanf("%d%lld%lld",&n,&bl,&br); for(int i=1;i<=n;++i)scanf("%d",&a[i]),mn=min(mn*1ll,a[i]?a[i]*1ll:INF); for(int i=0;i<mn;++i)for(int j=1;j<=n;++j)add(i,(i+a[j])%mn,a[j]); SPFA(); printf("%lld",ANS(br)-ANS(bl-1)); return 0; }
[2019.2.28]BZOJ2118 墨墨的等式