1. 程式人生 > 其它 >2612. [Poi2003]Sums 題解(同餘最短路)

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

不擺爛了,寫題