题目链接
题目思路
又学了一个神奇的东西叫做同余最短路
给出若干个数,每个数有无限个,问用这些数能组成(加起来)多少个不同的数
差不多是这个意思
对于这个题目来说
设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]。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
#define fi first
#define se second
#define debug printf("aaaaaaaaaaa\n");
const int maxn=1e6+5,inf=0x3f3f3f3f,mod=1e9+7,mul=233;
const ll INF=0x3f3f3f3f3f3f3f3f;
const double eps=1e-7;
int n,k;
int a[maxn];
int head[maxn],cnt;
int dis[maxn];
struct edge{
int to,next,w;
}e[maxn];
void add(int u,int v,int w){
e[++cnt]={v,head[u],w};
head[u]=cnt;
}
void dij(int x){
priority_queue<pii,vector<pii>,greater<pii> > que;
memset(dis,0x3f,sizeof(dis));
dis[x]=0;
que.push({0,x});
while(!que.empty()){
int len=que.top().first;
int pos=que.top().second;
que.pop();
if(len!=dis[pos]) continue;
for(int i=1;i<=n;i++){
if(dis[(pos+a[i])%a[1]]>dis[pos]+a[i]){
dis[(pos+a[i])%a[1]]=dis[pos]+a[i];
que.push({dis[(pos+a[i])%a[1]],(pos+a[i])%a[1]});
}
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
dij(0);
scanf("%d",&k);
for(int i=1,x;i<=k;i++){
scanf("%d",&x);
printf(dis[x%a[1]]<=x?"TAK\n":"NIE\n");
}
return 0;
}