ZOJ4101 Element Swapping

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) x1x2=(ij)(α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) y1y2=(ij)(α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. (y1y2)/(x1x2)=αi+αj.

现可以一边读取一边处理得到相应的 x = x 1 − x 2 , y = y 1 − y 2 x=x_1-x_2, y=y_1-y_2 x=x1x2,y=y1y2,
(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=(y1y2)/(x1x2)=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+(x1x2)/(α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;
	}
	```
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值