洛谷 P2662 牛场围栏

做法是这样的:

首先暴力把所有可能的边长搞出来。。(当然<=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\n",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\n",i,d[i]);
67     return 0;
68 }

 

posted @ 2018-08-02 22:00  hehe_54321  阅读(220)  评论(0编辑  收藏  举报
AmazingCounters.com