“玲珑杯”ACM比赛 Round #18 C -- 图论你先敲完模板

题目链接:图论你先敲完模板

题目大意: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);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值