你也可以进入我的博客进行查看

小苯的钟表显示

根据输入的秒数,分别算出小时,分钟和秒即可

void work()
{
   int n ; cin >> n ; 
    int h = n / 3600 ; 
    n %= 3600 ; 
    int f = n / 60 ;
    n %= 60 ; 
    cout << h << " " << f << " " << n << endl ; 
}

小苯的输入法

可以通过一个双端队列来维护输入端的左侧和右侧,可以通过设定一个标志cur来判断现在位于左端还是右端,需要注意的是,-不仅仅用于当前那一侧的删除,还可以删除另外一侧

void work()
{
    int n;
    cin >> n;
    string s;
    cin >> s;
    deque<char>q ; 
    int cur = 0;
    for (int i = 0; i < n; i++)
    {
        if(s[i] >= 'a' && s[i] <= 'z')
        {
            if(cur == 0)q.pb(s[i]) ; 
            else q.push_front(s[i]) ; 
        }
        else if(s[i] == '!')
        {
            cur = (cur + 1) % 2 ; 
        }
        else
        {
            if(q.size())
            {
                if(cur == 0)q.pop_back() ;
                else q.pop_front() ; 
            }
        }
    }
    if(q.size())
    {
        while(q.size())
        {
            cout << q.front() ; 
            q.pop_front() ; 
        }
        cout << endl ; 
    }
    else
    {
        cout << "Empty" ; 
        cout << endl ; 
    }
}

小苯的观景路线

题目要求选出的观景点坐标按照升序排序,所以我们先把得到的数组进行升序排序,按照贪心的思路来说,第一个选出的景点选第一个就好,然后向后遍历,按照题意求解即可

void work()
{
   int n ; cin >> n ; 
    vi a(n) ; 
    for(int i = 0 ; i < n ; i++)cin >> a[i] ; 
    sort(all(a)) ; 
    int mx = 1 ;
    int cur = a[0] ; 
    for(int i = 1 ; i < n ; i++)
    {
        if(a[i] - cur >= mx)
        {
            mx++ ; 
            cur = a[i] ; 
        }
    }
    cout << mx << endl ; 
}

小苯的序列涂色

由于每次选择的区间可以重叠,所以考虑使用区间dp进行操作,为了简化操作,预先处理一个前缀和。

这道题目dp的关键在于,我们选定前i段区间,然后维护一个最小值,再枚举前j段区间,所以我们的mini其实维护的就是i-j这段区间染色的代价,由于这段区间是只增不减的,所以我们的mini只需要找到最小值就可以了,题目允许同一位置被多次染色

void work()
{
   int n ; cin >> n ;
    vi a(n + 1 , 0) ; 
    vi pre(n + 1 , 0) ; 
    for(int i = 1 ; i <= n ; i++)cin >> a[i] , pre[i] = pre[i - 1] ^ a[i] ;
    vi dp(n + 5 , inf) ;
    dp[0] = 0 ; 
    for(int i = 1 ; i <= n ; i++)
    {
        int mini = inf ; 
        for(int j = 1 ; j <= i ; j++)
        {
            mini = min(mini , (pre[i] ^ pre[j - 1]));
            dp[i] = min(dp[i] , dp[j - 1] + mini) ;
        }
    }
    cout << min(dp[n] , pre[n]) << endl ; 
}

小苯的凝聚区间

注意到答案区间的特点必然是最大值和最小值分布在区间的两端,如果不满足这个条件,区间的长度可以缩短,使凝聚力更大,然后我们按照两种情况对凝聚力公式进行优化:

1、最大值位于左侧,最小值位于右侧

此时公式变形为(M - r) - (m - l) , 也就是一个元素减去自己的坐标

2、最大值位于右侧,最小值位于左侧

此时公式变形为(M + l) - (m + r) , 也就是一个元素加上自己的坐标

于是我们可以想到,遍历整个数组,把我们当前所在的元素当作区间的右端点,然后维护第一种情况的最大值,维护第二种情况的最小值,计算差值并统计答案

void work()
{
   int n ; cin >> n ;
    vi mp(n) ;
    for(int i = 0 ; i < n ; i++)cin >> mp[i] ;
    int ans = 0 ; 
    int mx = mp[0] + 0 ; 
    int mi = mp[0] - 0 ; 
    for(int i = 1 ; i < n ; i++)
    {
        int b1 = mp[i] + i ; 
        int c1 = mp[i] - i ; 
        ans = max({ans , c1 - mi , mx - b1}) ; 
        mi = min(mi , c1) ; 
        mx = max(mx , b1) ; 
    }
    cout << ans << endl ; 
}

小苯的糖果盒

前提:这道题目应用了贪心的一种较为困难的情况,基础模型是将a数组变为b数组,每次可以选择a数组中的两个元素,一个元素+1,一个元素-1,成本是这两个元素的距离,求完成的所消耗的最小代价,解决这类问题,我们需要维护a数组和b数组的前缀和,每次让ans加上a和b前i段前缀和的绝对值。

回到本题:显然这道题目没有明显的b数组,但是我们可以枚举b数组的情况,然后按照前提所提到的公式计算总成本,使得代价最小,考虑到使用dp,因为我们只考虑相邻亮相的关系,所以使用滚动dp进行优化,对于一个dp[i][j],i表示的是当前位置所放置的完全平方数的开根,j表示的是前i个元素的前缀和。

从i = 1枚举到i = n , 明显的,我们分别枚举前面数字的前缀和,再枚举前面所填的数字,这里进行了一次优化,因为考虑到题目要求所有盒子的糖果数量构成一个非递减序列,所以我们所填的数字(这里你可以认为我们所填的数字和前面所填的数字合并进行枚举)只能大于等于前面所填的数字,而mini就负责维护前面所填数字情况的最小代价,之后就是将过去的代价转移到现在的代价,然后dp滚动即可。

最后,我们枚举最后一个所填数字的取值就可以了。

void work()
{
    int n;
    cin >> n;
    vi a(n + 1, 0);
    for (int i = 1; i <= n; i++)
    {
        int x;
        cin >> x;
        a[i] = a[i - 1] + x;
    }
    int sum = a[n] ;
    vii dp(101 , vi(sum + 10 , inf)) ;
    dp[0][0] = 0 ; 
    for(int i = 1 ; i <= n ; i++)
    {
        vii ndp(101 , vi(sum + 10 , inf)) ; 
        for(int j = 0 ; j <= sum ; j++)
        {
            int mini = inf ;
            for(int k = 0 ; k <= 100 ; k++)
            {
                mini = min(mini , dp[k][j]) ; 
                if(k * k + j > sum)continue ;
                int c = abs(j + k * k - a[i]) ; 
                ndp[k][j + k * k] = min(ndp[k][j + k * k] , c + mini) ; 
            }
        }
        dp.swap(ndp);
    }
    int ans = inf ;
    for(int i = 0 ; i <= 100 ; i++)
    ans = min(ans , dp[i][sum]) ;
    if(ans >= inf)cout << -1 << endl ; 
    else cout << ans << endl ; 
}