• 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 }
  • 相关阅读:
    spring cloud 和 阿里微服务spring cloud Alibaba
    为WPF中的ContentControl设置背景色
    java RSA 解密
    java OA系统 自定义表单 流程审批 电子印章 手写文字识别 电子签名 即时通讯
    Hystrix 配置参数全解析
    spring cloud 2020 gateway 报错503
    Spring Boot 配置 Quartz 定时任务
    Mybatis 整合 ehcache缓存
    Springboot 整合阿里数据库连接池 druid
    java OA系统 自定义表单 流程审批 电子印章 手写文字识别 电子签名 即时通讯
  • 原文地址:https://www.cnblogs.com/Knightero/p/12804457.html
Copyright © 2020-2023  润新知