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;
}

  

posted @ 2015-08-07 15:13  Claris  阅读(656)  评论(0编辑  收藏  举报