题目链接:图论你先敲完模板 题目大意:n个点,然后一个人可以从一个点跑到另一个点,花费为pow(2,x[i]-x[j])+a,x[i]是第i个点的位置,最开始的时候这个人在第一个点,问他
题目链接:图论你先敲完模板
题目大意:n个点,然后一个人可以从一个点跑到另一个点,花费为pow(2,x[i]-x[j])+a,x[i]是第i个点的位置,最开始的时候这个人在第一个点,问他到第n个位置的时候需要的最少花费为多少
题目思路:我们可以很轻松的得到这样一个转移方程dp[i] = min(dp[i],dp[j]+pow(2,dp[i]-dp[j])+a)当然这里算2次方肯定不能用pow,用位运算就好了,但是如果我们这样转移下去的话,复杂度就是O(n*n)了,当然不行,所以我们考虑一下优化,因为是呈2的指数增长,所以我们可以知道在某个位置一定是远远大于a的,又因为x[i]-x[i-1]<=30,所以,我们可以知道从相邻的点转移,最多就为1<<30+maxa(1e6),所以,当x[i]-x[j]大于1<<30时,一定是不合法的,所以在这个临界我们剪一下,然后就可以写出来代码了
#include <bits/stdc++.h>using namespace std;
typedef long long ll;
const int maxn = 1e6+10;
ll t,n,a,x[maxn],dp[maxn];
int main(){
std::ios::sync_with_stdio(false);
cin>>t;
while(t--){
cin>>n>>a;
for(ll i = 1;i <= n;i++)
cin>>x[i];
memset(dp,0x3f3f3f3f,sizeof(dp));
dp[1] = 0;
for(ll i = 2;i <= n;i++){
for(int j = i-1;j >= 1;j--){
ll len = x[i]-x[j];
if(len > 30) break;
dp[i] = min(dp[i],dp[j]+(1ll<<len)+a);
}
}
cout<<dp[n]<<endl;
}
return 0;
}
//dp[i] = min(dp[i],dp[j]+1<<len+a);