码迷,mamicode.com
首页 > 其他好文 > 详细

T53865 蝴蝶的故事

时间:2018-10-29 22:56:42      阅读:165      评论:0      收藏:0      [点我收藏+]

标签:意思   复杂度   ons   fine   故事   print   include   lin   情况   

dlT1让人心态爆炸qwq

30pts做法:暴力or你的dp写挂(我就dp写挂了)

50pts做法:在dp里面注意一点,\(2^{cnt}\)可能会爆long long!那些求出来的答案明显爆long long的直接用整个序列的和\(10^{10}\)取min。

满分做法:

\(\lceil log_2{10^10} \rceil = 34\),意思是第34次以及以后,不用魔法,都大于整个序列的最大和。所以后面一定要用魔法了,不用肯定不优秀。

所以设\(dp[i]\)为用了\(i\)次魔法的最短时间。这里滚动掉了一维,所以枚举用魔法的次数要倒推枚举。

所以魔法枚举到\(33\)为止,后面的直接视为一种情况,直接在原第33次使用魔法的时间基础上加上\(\sum_{i=34}{i+log_2{a_i}}\),这个东西可以\(O(1)\)地求出来。

所以复杂度是\(O(nlogn)\)的。。。

代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
const int maxn = 100005;
const ll maxv = 1e10;
const int lim = 34;
ll a[maxn], n;
ll luog[maxn];
ll dp[maxn];
ll ans = 1e18;

ll read()
{
    ll ans = 0, s = 1;
    char ch = getchar();
    while(ch > ‘9‘ || ch < ‘0‘){ if(ch == ‘-‘) s = -1; ch = getchar(); }
    while(ch >= ‘0‘ && ch <= ‘9‘) ans = ans * 10 + ch - ‘0‘, ch = getchar();
    return s * ans;
}
int main()
{
    memset(dp, 0x3f, sizeof dp);
    n = read();
    for(int i = 1; i <= n; i++)
    {
        a[i] = read();
        luog[i] = luog[i - 1] + (int)(log2(a[i]));
        ans += a[i];
    }
    dp[0] = 0;
    for(int i = 1; i <= n; i++)
    {
        for(int j = lim - 1; j >= 1; j--)
        {
            if((maxv >> j) >= a[i]) dp[j] = std::min(dp[j] + (a[i] << j), dp[j - 1] + (int)(log2(a[i])) + j - 1);
            else dp[j] = dp[j - 1] + (int)(log2(a[i])) + j - 1;
        }
        dp[0] += a[i];
        ans = std::min(ans, dp[lim - 1] + luog[n] - luog[i] + (n - i) * (2 * lim + n - i - 3) / 2);
    }
    for(int i = 0; i < lim; i++) ans = std::min(ans, dp[i]);
    printf("%lld\n", ans);
    return 0;
}

T53865 蝴蝶的故事

标签:意思   复杂度   ons   fine   故事   print   include   lin   情况   

原文地址:https://www.cnblogs.com/Garen-Wang/p/9873668.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!