地址:http://acm.uestc.edu.cn/#/problem/show/1633
题目:
去年春恨却来时,落花人独立,微雨燕双飞
Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
给你一个大小为n的集合S,集合里有n个互不相同正整数.
有q个询问,每次询问是否能选择S中的一些数字 ( 同一个数字可以选择多次,也可以任何数字都不选),使它们相加的和为m.
Input
第一行一个数n(1≤n≤2000),表示集合S的大小.
第二行n个数,第ii个数ai(1≤ai≤50000)表示集合S中的第ii个数.
第三行一个数q(1≤q≤10000),表示询问次数.
接下来q行,每行一个数m(0≤m≤1000000000),表示该次询问的数.
Output
每次询问输出一行,如果存在和为m的方法,输出YES,否则输出NO.
Sample input and output
Sample Input | Sample Output |
---|---|
3 2 4 9 4 6 7 18 25 |
YES NO YES YES |
Hint
对于第一个询问,存在2+2+2=6,所以输出YES
对于第一个询问,无法构造,输出NO
对于第三个询问,存在9+9=18,所以输出YES
对于第四个询问,存在2+2+4+4+4+9=25,所以输出YES
Source
2017 UESTC Training for Graph Theory
思路:
设集合中最小的数为p。假如现在知道x能被表示出来,那么x+ai必然也能够被表示出来。
记d[x]为所能表示的所有模p为x的数中的最小值,那么d[x]+k*p的所有数也必然能被表示出来。
所以考虑模p的所有剩余系,可以判断任意数字是否可以被表示。
然后题目就转化成了求d[x]的最短路问题。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define MP make_pair 6 #define PB push_back 7 typedef long long LL; 8 typedef pair<int,int> PII; 9 const double eps=1e-8; 10 const double pi=acos(-1.0); 11 const int K=5e4+7; 12 const int mod=1e9+7; 13 14 int n,m; 15 int v[K],d[K],vis[K],mi=mod; 16 void spfa(void) 17 { 18 memset(d,0x3f3f3f3f,sizeof d); 19 queue<int>q; 20 q.push(0),d[0]=0,vis[0]=1; 21 while(q.size()) 22 { 23 int x=q.front(); 24 q.pop(),vis[x]=0; 25 for(int i=1;i<=n;i++) 26 { 27 int y=(x+v[i])%mi; 28 if(d[x]+v[i]<d[y]) 29 { 30 d[y]=d[x]+v[i]; 31 if(!vis[y]) q.push(y),vis[y]=1; 32 } 33 } 34 } 35 } 36 int main(void) 37 { 38 scanf("%d",&n); 39 for(int i=1;i<=n;i++) 40 scanf("%d",v+i),mi=min(mi,v[i]); 41 spfa(); 42 scanf("%d",&m); 43 int x; 44 while(m--) 45 { 46 scanf("%d",&x); 47 if(d[x%mi]<=x) printf("YES "); 48 else printf("NO "); 49 } 50 return 0; 51 }