zoukankan      html  css  js  c++  java
  • Codeforces Round#636(Div.3) D题 差分数组

     题意

    给定一组数组a,我们可以把数组a的任意数调整为1到k里的一个数,要求a[i]与a[n-i+1]的和是定值x(i<n/2)

    这道题一开始我的思路是拿到一对数,可以知道在哪个范围内的定值x需要修改一次,两次或者不修改

    然后产生了如下代码(没AC)

     1 #include <iostream>
     2 #include <cmath>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 const int INF = 0x3f3f3f3f;
     7 int a[400100];
     8 int p[400010] ;
     9 int main()
    10 {
    11     ios::sync_with_stdio(false);
    12     cin.tie(0);
    13     cout.tie(0);
    14     int t;
    15     cin >> t;
    16     while (t--)
    17     {
    18         memset(p, 0, sizeof(p));
    19         
    20         int n, k;
    21         cin >> n >> k;
    22         for (int i = 1; i <= n; i++) cin >> a[i];
    23         for (int i = 1; i <= n / 2; i++)
    24         {
    25             int l = min(a[i], a[n - i + 1]) + 1;
    26             int r = max(a[i], a[n - i + 1]) + k;
    27             int sum = a[i] + a[n - i + 1];
    28             for (int j = 2; j <= 2 * k; j++)
    29             {
    30                 if (j == sum)continue;
    31                 else
    32                 {
    33                     if (j <= r && j >= l) p[j]++;
    34                     else p[j] += 2;
    35                 }
    36             }
    37 
    38 
    39         }
    40         int mini = INF;
    41         for (int i = 2; i <= 2 * k; i++)
    42         {
    43            
    44            mini = min(mini, p[i]);
    45           
    46          }
    47         cout << mini << endl;
    48 
    49     }
    50     return 0;
    51 }

    我是想算出已知两个数的范围,如果知道两个数a[i]和a[n-i+1]就可以算出范围

    左边界 left=min(a[i],a[n-i+1])+1

    右边界 right=max(a[i],a[n-i+1)+k

    p[x]是指x为目标的两数和定值,在左边界和右边界之间的x且x不等于sum,p[x]都要+1,因为要修改一个值才能达到

    x等于sum就不加

    都不满足则+2

    但是这道题如果这样子做要加很多次,就会导致tle

    这时候就要用差分数组来优化,有点类似线段树的lazytag

    从对p[2]每次循环+2;(如果暂时看不懂继续往下)

    现在把范围进行拆分

    2~left-1 都要+2

    left~sum-1 +1

    sum +0

    sum-1~right +1

    right+1~2*k +2

    我们第一次循环p[2]的值是为2,意味着后面每一个数都要+2

    然后走到left,这里我们进行了p[left]--的操作让p[left]的值为-1

    那么遍历到left之后的值,就要每一个数+2-1,即为+1

    下面的操作同理

    其实和我的第一个思路的差别就是

    我的第一个思路是一个一个加,而第二个思路是一起加,先存起来

     1 #include <iostream>
     2 #include <cmath>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 const int INF = 0x3f3f3f3f;
     7 int a[400100];
     8 int p[400010] ;
     9 int main()
    10 {
    11     ios::sync_with_stdio(false);
    12     cin.tie(0);
    13     cout.tie(0);
    14     int t;
    15     cin >> t;
    16     while (t--)
    17     {
    18         memset(p, 0, sizeof(p));
    19         
    20         int n, k;
    21         cin >> n >> k;
    22         for (int i = 1; i <= n; i++) cin >> a[i];
    23         for (int i = 1; i <= n / 2; i++)
    24         {
    25             int l = min(a[i], a[n - i + 1]) + 1;
    26             int r = max(a[i], a[n - i + 1]) + k;
    27             int sum = a[i] + a[n - i + 1];
    28             p[2] += 2;
    29             p[l]--;
    30             p[r + 1]++;
    31             p[sum]--;
    32             p[sum+1]++;
    33 
    34 
    35         }
    36         int mini = INF;
    37         for (int i = 2; i <= 2 * k; i++)
    38         {
    39            p[i] += p[i-1];
    40            mini = min(mini, p[i]);
    41           
    42          }
    43         cout << mini << endl;
    44 
    45     }
    46     return 0;
    47 }
  • 相关阅读:
    给函数中的形参设置默认值
    css-文字一行显示效果
    考试倒计时-通过开始时间字符串和间隔时间戳设置考试倒计时
    vue父向子传值,子组件无法及时更新父组件传过来的值的问题
    vue+elementUI在输入框中按回车键会刷新页面
    前端面试题记录
    Web是如何工作的:基本架构和原理
    JavaScript构造函数和原型概述
    js byte字节流和数字,字符串之间的转换,包含无符和有符之间的转换
    C#串口通讯,复制粘贴就可用,仅仅介绍怎样最快的搭建一个串口通讯,异常拦截等等需要自己加上
  • 原文地址:https://www.cnblogs.com/Knightero/p/12804457.html
Copyright © 2011-2022 走看看