The 16th Zhejiang Provincial Collegiate Programming Contest Promlem B Element Swapping
题目链接: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4101
题意:
题目求有多少种交换方案,使得交换数列中两个元素 α i , α j ( i ! = j ) \alpha_i,\alpha_j(i!=j) αi,αj(i!=j),有交换后得到 x 2 = ∑ 1 n k α k , y 2 = ∑ 1 n k α k 2 x_2=\sum_1^nk\alpha_k,y_2=\sum_1^nk\alpha_k^2 x2=∑1nkαk,y2=∑1nkαk2题目所给的 x 1 , y 1 x_1,y_1 x1,y1,相等。
解法:
记交换的元素
α
i
,
α
j
(
i
!
=
j
)
\alpha_i,\alpha_j(i!=j)
αi,αj(i!=j),则经过化简可以得到条件:
①
x
1
−
x
2
=
(
i
−
j
)
(
α
j
−
α
i
)
x_1-x_2=(i-j)(\alpha_j-\alpha_i)
x1−x2=(i−j)(αj−αi)
②
y
1
−
y
2
=
(
i
−
j
)
(
α
j
−
α
i
)
(
α
j
+
α
i
)
y_1-y_2=(i-j)(\alpha_j-\alpha_i)(\alpha_j+\alpha_i)
y1−y2=(i−j)(αj−αi)(αj+αi)
其中②可以转化为
(
y
1
−
y
2
)
/
(
x
1
−
x
2
)
=
α
i
+
α
j
.
(y_1-y_2)/(x_1-x_2)=\alpha_i+\alpha_j.
(y1−y2)/(x1−x2)=αi+αj.
现可以一边读取一边处理得到相应的
x
=
x
1
−
x
2
,
y
=
y
1
−
y
2
x=x_1-x_2, y=y_1-y_2
x=x1−x2,y=y1−y2,
(1)在
x
!
=
0
x!=0
x!=0的情况下,可以得到
s
u
m
=
(
y
1
−
y
2
)
/
(
x
1
−
x
2
)
=
y
/
x
=
α
i
+
α
j
sum=(y_1-y_2)/(x_1-x_2)=y/x=\alpha_i+\alpha_j
sum=(y1−y2)/(x1−x2)=y/x=αi+αj,。遍历数组,当前为
α
i
\alpha_i
αi,则对应的
t
a
r
g
e
t
=
α
j
=
s
u
m
−
α
i
target=\alpha_j=sum-\alpha_i
target=αj=sum−αi,通过条件①可以得到
j
=
i
+
(
x
1
−
x
2
)
/
(
α
j
−
α
i
)
j=i+(x_1-x_2)/(\alpha_j-\alpha_i)
j=i+(x1−x2)/(αj−αi),这时只需要检查数组中
α
j
\alpha_j
αj是否等于
t
a
r
g
e
t
target
target,若等于答案加一,很容易想到这样遍历之后会计两遍(i和j换 j和i换,其中i < j),故最后答案还要除以2。
(2)在
x
=
0
x=0
x=0的情况下,由①②可知
y
y
y一定也为0,所以y不为0的情况下交换次数为0,而y=0时能交换的只有数值大小相同的元素。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e5 + 10;
int T, N, a[MAX];
ll x, y;
map<int, int> mp;//储存num出现了几次
int main() {
scanf("%d", &T);
while (T--) {
mp.clear();
ll cnt = 0;
scanf("%d%lld%lld", &N, &x, &y);
for (int i = 1; i <= N; i++) {
scanf("%d", &a[i]);
mp[a[i]]++;
x -= 1ll * i * a[i];
y -= 1ll * i * a[i] * a[i];
}
if (x == 0) {//说明a[i] == a[j],则y必然为0
if (y) {//y不为0 不能交换
printf("0\n");
continue;
}
for (int i = 1; i <= N; i++)//相等的数可以互换
cnt += mp[a[i]] - 1;
}
else {//x不为0
if (y % x) {//不能整除说明a[i]+a[j]不是整数 不能交换
printf("0\n");
continue;
}
ll sum = y / x;
for (int i = 1; i <= N; i++) {
ll target = sum - a[i];
if (a[i] == target)continue;//防止除数为0
int j = i + x / (a[i] - target);
if (j >= 1 && j <= N && a[j] == target)cnt++;
}
}
printf("%lld\n", cnt / 2);
}
return 0;
}
```