题目
Atcoder
有
n
n
n 只骆驼,第
i
i
i 只重量为
w
i
w_i
wi 现在通过
m
m
m 座桥,每个桥长度为
l
i
l_i
li,承重为
v
i
v_i
vi (允许骆驼踩在端点
0
0
0 和
l
i
l_i
li ),安排骆驼顺序使得队列长度最小
n
≤
8
,
m
≤
1
0
5
n\le 8,m\le10^5
n≤8,m≤105
思路
首先排列枚举骆驼过桥顺序,然后
d
p
dp
dp 检验
f
i
f_i
fi :前
i
i
i 只骆驼过桥最短长度
f
1
=
0
f_1=0
f1=0
然后有
f i = m a x ( f j + l e n ( j , i ) ) f_i=max(f_j+len(j,i)) fi=max(fj+len(j,i))
考虑为什么合理
然后考虑如何快速求出
l
e
n
len
len ,判断一段骆驼最短长度
可以发现路长承重对路短的有限制
然后路按长度升序,承重也升序了
找到最长的无法承重的桥的长度就是这段骆驼的承重
确实比它短的可能也过不去
但就不是这段骆驼的问题了
代码
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<climits>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define int LL
int read(){
int f=0,x=0;char c=getchar();
while(c<'0'||'9'<c){if(c=='-')f=1;c=getchar();}
while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return !f?x:-x;
}
#define mp make_pair
const int MAXN=100000;
const int INF=1000000000000000000ll;
pair<int,int> c[MAXN+5];
int n,m,w[10],p[10],f[10],s[10];
int cal(int x){
int L=0,R=m+1;
while(L+1<R){
int Mid=(L+R)>>1;
if(c[Mid].second<x)
L=Mid;
else R=Mid;
}
return c[L].first;
}
signed main(){
n=read(),m=read();
for(int i=1;i<=n;i++)
w[i]=read(),p[i]=i;
for(int i=1;i<=m;i++)
c[i].first=read(),c[i].second=read();//l_i,v_i
sort(c+1,c+m+1);
int Min=INF;
for(int i=m;i>=1;i--)
Min=min(Min,c[i].second),c[i].second=Min;
for(int i=1;i<=n;i++)
if(Min<w[i]){
puts("-1");
return 0;
}
int ans=INF;
do{
memset(f,0,sizeof(f));
for(int i=1;i<=n;i++)
s[i]=s[i-1]+w[p[i]];
for(int i=2;i<=n;i++)
for(int j=1;j<=i-1;j++)
f[i]=max(f[i],f[j]+cal(s[i]-s[j-1]));
ans=min(ans,f[n]);
}while(next_permutation(p+1,p+n+1));
printf("%lld\n",ans);
return 0;
}