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 }
原文地址:https://www.cnblogs.com/Knightero/p/12804457.html