P2662 牛场围栏 同余最短路
链接:https://www.luogu.com.cn/problem/P2662
题目要求求出最大不能拼凑出来的木板长度,因此我们把最短的木板作为剩余系,扫描其他的木板并建边。题目另外说每个木板可以最多截掉m米,那么只要再扫描到每个木板的时候依次扫描这个木板能被截成的长度就好了。
如何解决不能凑出来的最大木板长度?我们求出的dist[]数组是不使用(a[1]-m)的长度外能凑出来的最小长度,那么只要从dist[]中减去这个值就能得出剩余系中这类不能拼凑的最大值。对所有类都进行这样的处理,最终就能得出不能凑出的最大值。
此外题目特判任意长度都可以拼成或最大值不存在输出"-1"。先考虑任意长度都能拼成,如果这个木板的长度能被削成1,那么一定可以达到任意长度,对应为if(a[1]-m<=1)
[2]。最大值不存在的情况为剩余系中一类数都无法拼成,即dist[k]没有被松弛。
代码如下:
1 #include<bits/stdc++.h> 2 #define N 2500010 3 #define INF 0x3f3f3f3f 4 using namespace std; 5 int n,m,ans,a[500],dist[N<<1],vis[N<<1],tot; 6 int first[N],next[N<<1],go[N<<1],cost[N<<1]; 7 inline void add_edge(int u,int v,int w){ 8 next[++tot]=first[u]; 9 first[u]=tot; 10 go[tot]=v; 11 cost[tot]=w; 12 } 13 inline void spfa(){ 14 queue<int> q; 15 memset(dist,INF,sizeof(dist)); 16 memset(vis,0,sizeof(vis)); 17 dist[0]=0;vis[0]=1; 18 q.push(0); 19 while(!q.empty()){ 20 int u=q.front();q.pop(); 21 vis[u]=0; 22 for(int e=first[u];e;e=next[e]){ 23 int v=go[e],w=cost[e]; 24 if(dist[v]>dist[u]+w){ 25 dist[v]=dist[u]+w; 26 if(!vis[v]){ 27 q.push(v);vis[v]=1; 28 } 29 } 30 } 31 } 32 } 33 int main() 34 { 35 scanf("%d%d",&n,&m); 36 for(int i=1;i<=n;i++) scanf("%d",&a[i]);//木棒长度 37 sort(a+1,a+n+1); 38 if(a[1]-m<=1){printf("-1");return 0;}//任意长度都能达到 39 for(int i=1;i<=n;i++)//扫描每根木棒 40 for(int j=max(a[i]-m,a[i-1]+1);j<=a[i];j++)//扫描木棒能削出来的长度,其中max()保证不重复 41 for(int k=0;k<a[1]-m;k++) add_edge(k,(k+j)%(a[1]-m),j);//0~a[1]-1 作为剩余系,操作同例1 42 spfa(); 43 for(int i=1;i<=a[1]-m-1;i++){ 44 if(dist[i]>100000000){//最大值不存在,mod x=i这一类数全凑不出来 45 printf("-1");return 0; 46 } 47 ans=max(ans,dist[i]-(a[1]-m)); 48 } 49 printf("%d",ans); 50 return 0; 51 }