1. 程式人生 > 實用技巧 >[noi.ac 模擬賽9] A.出征準備(同餘最短路)

[noi.ac 模擬賽9] A.出征準備(同餘最短路)

題目

題目描述

dkw 的劍需要 \(t\) 點能量, 黑市有 \(n\) 種充能水晶, 每種充能水晶有它的能量值 \(V_i\)

dkw 有無限的錢, 可以買任意種水晶任意個(不能買負數個)。

由於 dkw 的劍必須剛好充滿能量才能使用,所以你需要回答他是否存在一種方案,剛好充滿 dkw 的劍的能量。

輸入格式

第一行是一個 \(T\) , 代表測試資料組數

對於每組測試資料, 第一行有兩個整數 \(n, t\)
接下來 \(n\) 行, 每行一個整數, \(V_i\)

輸出格式

對於每組測試資料, 如果能, 輸出 Possible ; 否則輸出 Impossible

資料範圍

\(1≤T≤10, 1≤n≤50, 1≤t≤10^{18}, 0≤V_i≤10^4\)

題解

\(V_1\)\(\{V\}\) 中最小的。設 \(dist[i]\) 表示經過 \(V_2,...,V_n\) 的加法,最小的 \(p \equiv i \pmod{V_1}\)。跑一個同餘最短路就好了。

\(m=Vn\),時間複雜度 \(O(Tm \log m)\)

程式碼

Talk is cheap.Show me the code.

#include<bits/stdc++.h>
#define int long long
#define mp make_pair
#define fi first
#define se second
using namespace std;
inline int read() {
    int x = 0, f = 1; char ch = getchar();
    while(ch<'0' || ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<3)+(x<<1)+(ch^48); ch=getchar(); }
    return x * f;
}
typedef pair<int,int> PII;
const int N = 1e4+7;
int t,n,cnt;
int V[N],head[N];
struct Edge {
	int next,to,w;
}edge[N*50];
inline void add(int u,int v,int w) {
	edge[++cnt] = (Edge)<%head[u],v,w%>;
	head[u] = cnt;
}
int dist[N];	//dist[i] 最小的 p≡i(mod V[1]) 
bool vis[N];
void Dijkstra() {
	memset(dist, -1, sizeof(dist));
	memset(vis, 0, sizeof(vis));
	priority_queue<PII> q;
	dist[0] = 0;
	q.push(mp(-dist[0],0));
	while(!q.empty()) {
		int u = q.top().se;
		q.pop();
		if(vis[u]) continue;
		vis[u] = 1;
		for(int i=head[u];i;i=edge[i].next) {
			int v = edge[i].to, w = edge[i].w;
			if(dist[u]+w > t) continue;
			if(dist[v]==-1 || dist[v]>dist[u]+w) {
				dist[v] = dist[u] + w;
				q.push(mp(-dist[v],v));
			}
		}
	}
}
void work() {
	memset(head, 0, sizeof(head));
	cnt = 0;
	n = read(), t = read();
	for(int i=1;i<=n;++i) V[i] = read();
	sort(V+1,V+1+n);
	for(int i=0;i<V[1];++i) {
		for(int j=2;j<=n;++j) {
			add(i,(i+V[j])%V[1],V[j]);
		}
	}
	Dijkstra();
	if(dist[t%V[1]]==-1 || dist[t%V[1]]>t) puts("Impossible");
	else puts("Possible");
}
signed main()
{
	int T = read();
	while(T--) work();
    return 0;
}
/*
1
4 78  
12
5
7
9

Possible
*/

總結

同餘最短路的一般套路。