zoukankan      html  css  js  c++  java
  • hdu1500 (排序+单调队列优化 )

    从n根筷子里面, 选择k+8个集合的筷子,每个集合三根筷子, A<=B<=C, 费用是(A-B)^2,

    问最小的费用是多少。

    将n根筷子排序之后,可以知道A和B的下标一定是连续的。

    比如有 A B C D ,  那么不可能是A C 一个集合, B D一个集合, 因为这样费用反而更大。

    设dp[i][j] 为第i个集合的筷子,以j结尾,  就是说 A和B分别是第j和第j-1个筷子

    dp[i][j] = min(dp[i-1][k]) + (a[j]-a[j-1])^2

    那么如何处理第三根筷子呢?

    只要将筷子从大到小排序。

    dp[i][j] 的j是从3*i开始的,

    而dp[i-1][k]的k是从(i-1)*3开始的,这样就保证了每个集合在前面的筷子中,都有一根筷子与自己配对。

    dp[i][j] = min(dp[i-1][k]) + (a[j]-a[j-1])^2  这个循环可以用单调递增队列来优化,保证队头最小就行了。

    #pragma warning(disable:4996)
    #pragma comment(linker, "/STACK:1024000000,1024000000")
    #include <stdio.h>
    #include <string.h>
    #include <time.h>
    #include <math.h>
    #include <map>
    #include <set>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <bitset>
    #include <algorithm>
    #include <iostream>
    #include <string>
    #include <functional>
    #include <unordered_map>
    typedef __int64 LL;
    const int INF = 999999999;
    
    /*
    A B 绝逼是连续的,问题是C怎么怎么描述
    dp[i][j]   第i套筷子是由j结束
    
    dp[i][j] = min(dp[i][j],dp[i-1][k])
    */
    
    const int N = 5000 + 10;
    int a[N];
    int dp[1111][N];
    int q[N], head, tail;
    int main()
    {    
        int t, n, k;
        scanf("%d", &t);
        while (t--)
        {
            scanf("%d%d", &k, &n);
            k += 8;
            for (int i = 1;i <= n;++i)
                scanf("%d", &a[i]);
            std::sort(a + 1, a + n + 1,std::greater<int>());
            for (int i = 1;i <= k;++i)
            {
                head = tail = 0;
                for (int j = (i-1)*3;j <= 3 * i - 2;++j)
                {
                    while (head < tail && dp[i - 1][q[tail - 1]] >= dp[i - 1][j])
                        tail--;
                    q[tail++] = j;
                }
                for (int j = 3 * i; j <= n;++j)
                {
                    dp[i][j] = (a[j] - a[j - 1])*(a[j] - a[j - 1]) + dp[i - 1][q[head]];
                    while (head < tail && dp[i - 1][q[tail - 1]] >= dp[i - 1][j-1])
                        tail--;
                    q[tail++] = j - 1;
                }
            }
            int ans = INF;
            for (int j = 3 * k;j <= n;++j)
                ans = std::min(ans, dp[k][j]);
            printf("%d
    ", ans);
            
        }
        return 0;
    }
  • 相关阅读:
    WPF 文本动画 文字BaseLine 字体 行高计算说明
    C#查找窗口,并控制窗口显示隐藏,通过改变窗口样式方式
    c#获取状态栏图标并-模拟鼠标点击-模拟鼠标点击窗体的某些按钮
    IEC 104公约 解析 c#使用通过104公约同步时间
    hprose数据可视化显示,通过c#序列化,列表形式展示,导出excel、csv
    微服务优秀博文资料
    IT 常用单词表
    java 优秀开源项目
    java并发编程学习博客
    LDAP服务端
  • 原文地址:https://www.cnblogs.com/justPassBy/p/4782862.html
Copyright © 2011-2022 走看看