zoukankan      html  css  js  c++  java
  • toj 4353 Estimation(树状数组+二分查找)

    Estimation

    时间限制(普通/Java):5000MS/15000MS     运行内存限制:65536KByte
    总提交: 6            测试通过: 1

    描述

     

    “There are too many numbers here!” your boss bellows. “How am I supposed to make sense of all of this? Pare it down! Estimate!”
    You are disappointed. It took a lot of work to generate those numbers. But, you’ll do what your boss asks.
    You decide to estimate in the following way: You have an array A of numbers. You will partition it into k contiguous sections, which won’t necessarily be of the same size. Then, you’ll use a single number to estimate an entire section. In other words, for your array A of size n, you want to create another array B of size n, which has k contiguous sections. If i and j are in the same section, then B[i]=B[j]. You want to minimize the error, expressed as the sum of the absolute values of the differences (Σ|A[i]-B[i]|).

    输入

     

    There will be several test cases in the input. Each test case will begin with two integers on a line, n (1≤n≤2,000) and k (1≤k≤25, kn), where nis the size of the array, and k is the number of contiguous sections to use in estimation. The array A will be on the next n lines, one integer per line. Each integer element of A will be in the range from -10,000 to 10,000, inclusive. The input will end with a line with two 0s.

    输出

     

    For each test case, output a single integer on its own line, which is the minimum error you can achieve. Output no extra spaces, and do not separate answers with blank lines. All possible inputs yield answers which will fit in a signed 64-bit integer.
     

    样例输入

     

    7 2
    6
    5
    4
    3
    2
    1
    7
    0 0
    

    样例输出

     

    9
    

    题目来源

    The University of Chicago Invitational Programming Contest 2012

    题解:

    勉强卡过。。应该不是正解。。

    以前做过一道题。。在一个线段上给定几个点。。求一个点使得到各点的距离和最短。。。从小到大排序。。该点就是中间大的点。。偶数个的话。。中间两个点都可以

    dp[i][j]记录i到j最小的绝对值。。。

    树状数组t[i]用来记录大小为i的点的个数

    树状数组e[i]用来记录<=i的所有点的和

    求i到j这一段的中间值就是找t[mid] == (j - i + 1 + 1) / 2 偶数个的话。。取后一个。。

    之后找比 mid 小的所有点和sum1。。还有比 mid 大的所有点和sum2

    求比 mid 小的所有点的个数num1。。比 mid 大的点个数num2

    dp[i][j] = sum2 - sum1 + mid * (num1 - num2)

     

     1 #include <stdio.h>
     2 #include <string.h>
     3 const int N = 2005;
     4 const int Max = 20010;
     5 int a[N];
     6 int t[Max+10];
     7 int e[Max+10];
     8 int dp[N][N];
     9 int f[N][30];
    10 int Min(int a, int b){
    11     return a < b ? a : b;
    12 }
    13 
    14 int lowbit(int x){
    15     return x & (-x);
    16 }
    17 
    18 void add(int i, int val, int c[]){
    19     
    20     while(i <= Max){
    21         c[i] += val;
    22         i += lowbit(i);
    23     }
    24 }
    25 int sum(int i, int c[]){
    26     
    27     int ret = 0;
    28     while(i > 0){
    29         ret += c[i];
    30         i -= lowbit(i);
    31     }
    32     return ret;
    33 }
    34 int Bin_search(int v){
    35     
    36     int l = 1;
    37     int r = Max;
    38     while(l < r){
    39         int m = (l + r) >> 1;
    40         int p = sum(m, t);
    41         if(p >= v){
    42             r = m;
    43         }
    44         else{
    45             l = m + 1;
    46         }
    47     }
    48     return l;
    49 }
    50 int main()
    51 {
    52     int n, k;
    53     while(scanf("%d %d", &n, &k), n || k){
    54         int i, j, g;
    55         for(i = 1; i <= n; i++){
    56             scanf("%d", a+i);
    57             a[i] += 10005;
    58         }
    59         for(i = 1; i <= n; i++){
    60             
    61             memset(t, 0, sizeof(t));
    62             memset(e, 0, sizeof(e));
    63             for(j = i; j <= n; j++){
    64                 add(a[j], 1, t);
    65                 add(a[j], a[j], e);
    66                 int num = (j - i + 2) >> 1;
    67                 int mid = Bin_search(num);
    68             //    printf("mid = %d
    ", mid);
    69                 int sum1 = sum(mid - 1, e);
    70             //    printf("sum1 = %d
    ", sum1);
    71                 int sum2 = sum(Max, e) - sum(mid, e);
    72             //    printf("sum2 = %d
    ", sum2);
    73                 int num1 = sum(mid - 1, t);
    74             //    printf("num1 = %d
    ", num1);
    75                 int num2 = sum(Max, t) - sum(mid, t);
    76             //    printf("num2 = %d
    ", num2);
    77                 dp[i][j] = sum2 - sum1 + mid * (num1 - num2);
    78             //    printf("%d ", dp[i][j]);
    79             }
    80         }
    81         for(i = 1; i <= k; i++){
    82             for(j = 1; j <= n; j++){
    83                 f[j][i] = dp[1][j];
    84                 if(i == 1){
    85                     continue;
    86                 }
    87                 for(g = 1; g <= j; g++){
    88                     f[j][i] = Min(f[j][i], f[g-1][i-1] + dp[g][j]);        
    89                 }
    90                 //printf("%d ", f[j][i]);
    91             }
    92             //puts("");
    93         }
    94         printf("%d
    ", f[n][k]);
    95     }
    96     return 0;
    97 }

     

     

  • 相关阅读:
    微信小程序 阻止冒泡事件
    vant/weapp goodsaction 显示样式不正常问题
    微信小程序图表工具wxcharts
    webstorm 不识别 rpx 格式化出错
    小程序自定义 tabbar 以vant weapp 调试工具不显示,但是在真机显示
    小程序自定义 tabbar 以vant weapp为例
    TypeScript之环境搭建
    模块化打包工具webpack
    【纪中受难记】——Day2.感觉冤的慌
    计算机精英协会考核题 —— 第三题:斐波那契数
  • 原文地址:https://www.cnblogs.com/luotinghao/p/3399394.html
Copyright © 2011-2022 走看看