题意
给定一组数组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 }