BZOJ2612 : [Poi2003]Sums
设d[i]表示能拼出的x中满足x%a[0]=i的最小的x,其中d[0]=0。
若d[x%a[0]]<=x,则一定可以拼出x,否则一定不可以。
建出带权有向图,点的标号从0到a[0]-1,i号点向(i+a[j])%a[0]号点连边,边权为a[j]。
一遍Dijkstra求出单源最短路即可完成预处理。
时间复杂度$O(na_0\log a_0)$。
#include<cstdio> #include<vector> #include<algorithm> #include<queue> using namespace std; typedef pair<int,int>P; const int N=50010,inf=1000000010; int n,m,i,x,a[N],d[N];P t;priority_queue<P,vector<P>,greater<P> >Q; inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} int main(){ for(read(n);i<n;i++)read(a[i]);m=a[0]; for(i=1;i<m;i++)d[i]=inf;Q.push(P(0,0)); while(!Q.empty()){ t=Q.top();Q.pop(); if(d[t.second]<t.first)continue; for(x=t.second,i=1;i<n;i++)if(d[x]+a[i]<d[(x+a[i])%m])Q.push(P(d[(x+a[i])%m]=d[x]+a[i],(x+a[i])%m)); } for(read(n);n--;puts(d[x%m]<=x?"TAK":"NIE"))read(x); return 0; }