CF1305C Kuroni and Impossible Calculation
题目大意
给定一个长度为 n 的数组,数组元素互不相同,输出所有满足 1 <= i < j <=n 的| a[i] - a[j] |的乘积对m取模后的结果。
题目分析
一开始可能没什么思路,想到暴力。但是,2e5的数据范围,用暴力的O()肯定是无法做到的。
(对于数学比较好的同学,可以看一下这一段;但是,正解在这一段后面,此处只列出一种可能性)那么,我们对乘法的式子进行一下分析,发现,它符合范德蒙行列式:
那么,就可以考虑用FFT(快速傅里叶变换)或其他快速多项式算法,将时间复杂度压缩到O(nlogn),那么应该就能做了。
但是,作者数学不太好(恼),没有办法优化时间复杂度,那就只能优化数据范围了。
首先,对于数组a中的元素,如果存在任意 i ,j 满足| a[i] - a[j] |%m等于0,那么,不管其他情况如何,最终结果一定是0。所以,只要在输入的时候,判断一下,有没有两个元素对m取模后的结果相同(即,差为m的倍数)的情况,有则输出0,反之则暴力计算即可。
为什么加上这个条件,就可以暴力了呢?
注意到,任意一个数对m的取模结果必然在[0,m-1]区间内,也就是有m种可能性。那么,当数组大小n大于m时,必然存在一个值满足至少为两个数组元素取模后的结果,即存在i ,j 满足| a[i] - a[j] |%m等于0,那么最终答案一定为0。也就是说,我们只需要暴力运算 n < m 的情况,即把数据压缩到了1e3的范围,这个就可以用暴力的方法计算了。
代码实现
#include <iostream>
using namespace std;
int n, m, a[200010];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for (int i = 0; i < n; i++)cin >> a[i];
if (n > m)cout << "0";//如果n > m则答案为0,反之暴力运算
else {
long long ans = 1;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
ans = (ans * abs(a[i] - a[j])) % m;
}
}
cout << ans;
}
}