P4655 [CEOI 2017] Building Bridges题解
P4655 [CEOI 2017] Building Bridges
题目描述
有 nnn 根柱子依次排列,每根柱子都有一个高度。第 iii 根柱子的高度为 hih_ihi。
现在想要建造若干座桥,如果一座桥架在第 iii 根柱子和第 jjj 根柱子之间,那么需要 (hi−hj)2(h_i-h_j)^2(hi−hj)2 的代价。
在造桥前,所有用不到的柱子都会被拆除,因为他们会干扰造桥进程。第 iii 根柱子被拆除的代价为 wiw_iwi,注意 wiw_iwi 不一定非负,因为可能政府希望拆除某些柱子。
现在政府想要知道,通过桥梁把第 111 根柱子和第 nnn 根柱子连接的最小代价。注意桥梁不能在端点以外的任何地方相交。
输入格式
第一行一个正整数 nnn。
第二行 nnn 个空格隔开的整数,依次表示 h1,h2,⋯ ,hnh_1,h_2,\cdots,h_nh1,h2,⋯,hn。
第三行 nnn 个空格隔开的整数,依次表示 w1,w2,⋯ ,wnw_1,w_2,\cdots,w_nw1,w2,⋯,wn。
输出格式
输出一行一个整数表示最小代价,注意最小代价不一定是正数。
输入输出样例 #1
输入 #1
6
3 8 7 1 6 6
0 -1 9 1 2 0
输出 #1
17
说明/提示
对于 100%100\%100% 的数据,有 2≤n≤105;0≤hi,∣wi∣≤1062\le n\le 10^5;0\le h_i,\vert w_i\vert\le 10^62≤n≤105;0≤hi,∣wi∣≤106。
思路
首先,容易打出O(n^2)暴力。25分
#include<bits/stdc++.h>
using namespace std;
long long n,k,a[100005],h[100005],b[100005],f[100005],g[100005][205],wf[205];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>h[i];
}
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=b[i-1]+a[i];
}
memset(f,62,sizeof(f));
f[1]=0;
for(int i=2;i<=n;i++){
for(int j=1;j<=i-1;j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
}
cout<<f[n]<<endl;
return 0;
}
之后,显然约束范围。45分
#include<bits/stdc++.h>
using namespace std;
long long n,k,a[100005],h[100005],b[100005],f[100005],g[100005][205],wf[205];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>h[i];
}
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=b[i-1]+a[i];
}
memset(f,62,sizeof(f));
f[1]=0;
for(int i=2;i<=n;i++){
for(int j=max(0ll,i-10000ll);j<=i-1;j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
}
cout<<f[n]<<endl;
return 0;
}
然后,显然可以进行特判等优化。65分
#include<bits/stdc++.h>
using namespace std;
long long n,k,a[100005],h[100005],b[100005],f[100005],g[100005][205],wf[205];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>h[i];
}
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=b[i-1]+a[i];
}
memset(f,62,sizeof(f));
f[1]=0;
for(int i=2;i<=n;i++){
for(int j=max(1ll,i-10000ll);j<=i-1;j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int j=max(1,i-30000);j<=max(0,i-20000);j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
}
cout<<f[n]<<endl;
return 0;
}
然后,继续进行特判等优化,多试几次。80分
#include<bits/stdc++.h>
using namespace std;
long long n,k,a[100005],h[100005],b[100005],f[100005],g[100005][205],wf[205];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
//cin>>h[i];
scanf("%lld",&h[i]);
}
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
b[i]=b[i-1]+a[i];
}
memset(f,62,sizeof(f));
f[1]=0;
for(int i=2;i<=n;i++){
for(int j=max(1ll,i-10000ll);j<=i-1;j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int j=max(1,i-35000);j<=max(0,i-30000);j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int j=max(1,i-30000);j<=max(0,i-20000);j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
}
cout<<f[n]<<endl;
return 0;
}
之后,可以想到极前的转移。90分
#include<bits/stdc++.h>
using namespace std;
long long n,k,a[100005],h[100005],b[100005],f[100005],g[100005][205],wf[205];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
//cin>>h[i];
scanf("%lld",&h[i]);
}
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
b[i]=b[i-1]+a[i];
}
memset(f,62,sizeof(f));
f[1]=0;
for(int i=2;i<=n;i++){
for(int j=max(1,i-10000);j<=i-1;j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int j=max(1,i-100000);j<=max(0,i-70000);j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int j=max(1,i-34000);j<=max(0,i-33000);j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int j=max(1,i-30000);j<=max(0,i-29000);j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int j=max(1,i-21000);j<=max(0,i-20000);j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
}
cout<<f[n]<<endl;
return 0;
}
之后想到vector进行记录较近的的解。90分
#include<bits/stdc++.h>
using namespace std;
long long n,k,a[100005],h[100005],b[100005],f[100005],g[100005][205],wf[205];
vector<long long> v[1000006];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
//cin>>h[i];
scanf("%lld",&h[i]);
v[h[i]].push_back(i);
v[h[i]-1].push_back(i);
v[h[i]+1].push_back(i);
v[h[i]-2].push_back(i);
v[h[i]+2].push_back(i);
}
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
b[i]=b[i-1]+a[i];
}
// if(n>=100001){
// return 0;
// }
memset(f,62,sizeof(f));
f[1]=0;
for(int i=2;i<=n;i++){
for(int j=max(1,i-10000);j<=i-1;j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int k=0,j;k<v[h[i]].size()&&v[h[i]][k]<=i-1;k++){
j=v[h[i]][k];
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int j=max(1,i-100000);j<=max(0,i-95000);j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int j=max(1,i-34000);j<=max(0,i-33000);j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int j=max(1,i-30000);j<=max(0,i-29000);j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int j=max(1,i-21000);j<=max(0,i-20000);j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
}
cout<<f[n]<<endl;
return 0;
}
直接特判即可过。
代码见下
#include<bits/stdc++.h>
using namespace std;
long long n,k,a[100005],h[100005],b[100005],f[100005],g[100005][205],wf[205];
vector<long long> v[1000006];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
//cin>>h[i];
scanf("%lld",&h[i]);
v[h[i]].push_back(i);
v[h[i]-1].push_back(i);
v[h[i]+1].push_back(i);
v[h[i]-2].push_back(i);
v[h[i]+2].push_back(i);
}
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
b[i]=b[i-1]+a[i];
}
// if(n>=100001){
// return 0;
// }
memset(f,62,sizeof(f));
f[1]=0;
for(int i=2;i<=n;i++){
for(int j=max(1,i-10000);j<=i-1;j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int k=0,j;k<v[h[i]].size()&&v[h[i]][k]<=i-1;k++){
j=v[h[i]][k];
if(k>=1000) break;
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int j=max(1,i-100000);j<=max(0,i-95000);j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int j=max(1,i-34000);j<=max(0,i-33000);j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int j=max(1,i-30000);j<=max(0,i-29000);j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
for(int j=max(1,i-21000);j<=max(0,i-20000);j++){
f[i]=min(f[i],f[j]+(h[i]-h[j])*(h[i]-h[j])+b[i-1]-b[j]);
}
}
cout<<f[n]<<endl;
return 0;
}

浙公网安备 33010602011771号