2612. [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]。

参考链接

代码

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

posted @ 2021-11-13 15:11  hunxuewangzi  阅读(46)  评论(0编辑  收藏  举报