http://www.elijahqi.win/2017/07/16/luogu2662-vijos1054/
题目背景
小L通过泥萌的帮助,成功解决了二叉树的修改问题,并因此写了一篇论文,
成功报送了叉院(羡慕不?)。勤奋又勤思的他在研究生时期成功转系,考入了北京大学光华管理学院!毕业后,凭着自己积累下的浓厚经济学与计算机学的基础,成功建设了一个现代化奶牛场!
题目描述
奶牛们十分聪明,于是在牛场建围栏时打算和小L斗智斗勇!小L有N种可以建造围栏的木料,长度分别是l1,l2 … lN,每种长度的木料无限。
修建时,他将把所有选中的木料拼接在一起,因此围栏的长度就是他使用的木料长度之和。但是聪明的小L很快发现很多长度都是不能由这些木料长度相加得到的,于是决定在必要的时候把这些木料砍掉一部分以后再使用。
不过由于小L比较节约,他给自己规定:任何一根木料最多只能削短M米。当然,每根木料削去的木料长度不需要都一样。不过由于测量工具太原始,小L只能准确的削去整数米的木料,因此,如果他有两种长度分别是7和11的木料,每根最多只能砍掉1米,那么实际上就有4种可以使用的木料长度,分别是6, 7,10, 11。
因为小L相信自己的奶牛举世无双,于是让他们自己设计围栏。奶牛们不愿意自己和同伴在游戏时受到围栏的限制,于是想刁难一下小L,希望小L的木料无论经过怎样的加工,长度之和都不可能得到他们设计的围栏总长度。不过小L知道,如果围栏的长度太小,小L很快就能发现它是不能修建好的。因此她希望得到你的帮助,找出无法修建的最大围栏长度。
这一定难不倒聪明的你吧!如果你能帮小L解决这个问题,也许他会把最后的资产分给你1/8哦!
输入输出格式
输入格式:
输入的第一行包含两个整数N, M,分别表示木料的种类和每根木料削去的最大值。以下各行每行一个整数li(1< li< 3000),表示第i根木料的原始长度。
输出格式:
输出仅一行,包含一个整数,表示不能修建的最大围栏长度。如果任何长度的围栏都可以修建或者这个最大值不存在,输出-1。
输入输出样例
输入样例#1:
2 1
7 11
输出样例#1:
15
说明
40 % :1< N< 10, 0< M< 300
100 % :1< N< 100, 0< M< 3000
题解:
找一个最小的, 设为min1。 若最小的为1,则输出-1;
把比Min1小的数看成每一个点
某些长度%min1后,一定在这之间。可以发现,如果我们能够组成某个长度x, 且 y = x % min1; 又设X = y + i * min1,则我们一定能够组成所有的X 且X满足下列关系(X%min1== y);如果不能组成呢?那么我们一定不能组成任意一个X使得(X%min1== y); 也就是说,不能组成的最大长度是无限大,此时无解,输出-1
可以把同余类看成节点,从每个 x 到 (x+Ai) modmin1 连一条长度为 Ai 的边(Ai为每根围栏长度,min1为最短围栏长度),然后以0为起点求单源最短路。
如果最后距离中有inf那么这个点,这个同余类,一定是当前围栏凑不出来的输出-1
这题结合数论+spfa,一边加边一边spfa,我还是第一次见到
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#define N 330000
#define N1 3300
#define inf 0x7fffffff
using namespace std;
queue<int> q;
int dis[N1];
bool flag[N1];
inline int read(){
int x=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x;
}
int n,m,a[N];
inline int min(int x,int y){
return x<y?x:y;
}
inline int max(int x,int y){
return x>y?x:y;
}
int main(){
//freopen("2662.in","r",stdin);
//freopen("2662.out","w",stdout);
n=read();m=read();
int num=n,min1=inf;
for (int i=1;i<=n;++i) {a[i]=read();if (a[i]<min1) min1=a[i];}
for (int i=1;i<=n;++i){
int minn=min(a[i],m);
for (int j=1;j<=minn;++j){
if (a[i]-j>0) {a[++num]=a[i]-j;if (a[num]<min1) min1=a[num];}
}
}
if (min1==1) {
printf("-1");return 0;
}
sort(a+1,a+num+1);
num=unique(a+1,a+num+1)-a-1;
// for (int i=1;i<=num;++i) printf("%d ",a[i]);
for (int i=0;i<min1;++i) dis[i]=inf;
memset(flag,false,sizeof(flag));
dis[0]=0;q.push(0);flag[0]=true;
while (!q.empty()){
int u=q.front();
for (int i=2;i<=num;++i){
int tmp=(u+a[i])%min1;
if (dis[u]+a[i]<dis[tmp]){
dis[tmp]=dis[u]+a[i];
if (!flag[tmp]) {
flag[tmp]=true;
q.push(tmp);
}
}
}
q.pop();
flag[u]=false;
}
int maxx=0;
for (int i=0;i<min1;++i) if(dis[i]==inf) {
printf("-1");return 0;
}else{
maxx=max(maxx,dis[i]);
}
printf("%d",maxx-min1);
return 0;
}