做法是这样的:
首先暴力把所有可能的边长搞出来。。(当然<=0的不要)
排序边长+去重,
当且仅当可行边长里面有1时,任何长度都能取到,输出-1
当且仅当所有可行边长的gcd大于1时,不能取到的长度没有上限,输出-1
其他情况,一定有解;设最短的可行边长为x
将所有可行边长按除以x的余数分类,一类建立一个点(除以x的余数为u,则建立u点)
对于每一个可行边长y,对于每一个点u,从点u向点(u+y)%x连一条长度为y的边
可以发现从0号点向任意点u的最短路长度(dijkstra跑出来)(设为d),就是所有能取到的总长度中,除以x的余数为u的之中,最短的;且这一类(指除以x的余数为u的长度)中,所有大于d的长度也都能取到(只要加上一些长度为x的边就行了);因此,d-x就不能取到了
那么最大的不能取到的就是所有“d-x”的最大值(等于“所有d的最大值”-x)
严谨一些的证明要比noip那道复杂很多啊。。根本不会,以后再说吧
https://blog.csdn.net/Timsei/article/details/63254318
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 #include<queue> 6 using namespace std; 7 #define fi first 8 #define se second 9 #define mp make_pair 10 #define pb push_back 11 typedef long long ll; 12 typedef unsigned long long ull; 13 typedef pair<int,int> pii; 14 int n,m; 15 int tt[300100]; 16 priority_queue<pii,vector<pii>,greater<pii> > q; 17 int d[3010],mm=-0x3f3f3f3f; 18 bool vis[3010]; 19 int main() 20 { 21 int i,j,u,v;pii t; 22 scanf("%d%d",&n,&m); 23 for(i=1;i<=n;i++) 24 { 25 scanf("%d",&u); 26 for(j=0;j<=m;j++) 27 { 28 if(u-j<=0) break; 29 tt[++tt[0]]=u-j; 30 } 31 } 32 sort(tt+1,tt+tt[0]+1);tt[0]=unique(tt+1,tt+tt[0]+1)-tt-1; 33 if(tt[1]==1) 34 { 35 puts("-1"); 36 return 0; 37 } 38 int g=tt[1]; 39 for(i=2;i<=tt[0];i++) g=__gcd(g,tt[i]); 40 if(g!=1) 41 { 42 puts("-1"); 43 return 0; 44 } 45 memset(d,0x3f,sizeof(d)); 46 q.push(mp(0,0));d[0]=0; 47 while(!q.empty()) 48 { 49 t=q.top();q.pop(); 50 u=t.se; 51 if(vis[u]) continue; 52 vis[u]=1; 53 for(i=1;i<=tt[0];i++) 54 { 55 v=(u+tt[i])%tt[1]; 56 //printf("%d %d ",u,v); 57 if(d[v]>d[u]+tt[i]) 58 { 59 d[v]=d[u]+tt[i]; 60 q.push(mp(d[v],v)); 61 } 62 } 63 } 64 for(i=0;i<tt[1];i++) mm=max(mm,d[i]); 65 printf("%d",mm-tt[1]); 66 //for(i=0;i<tt[1];i++) printf("%d %d ",i,d[i]); 67 return 0; 68 }