*题解:CF1188B Count Pairs
解析
观察 \((x + y)(x ^ 2 + y ^ 2)\),发现左边因式是一次,右边是二次。
考虑把左边也变成二次,做法是利用平方差公式,乘一个 \((x - y)\),变为:
\[(x ^ 2 - y ^ 2)(x ^ 2 + y ^ 2)
\]
再次利用平方差公式,变为:
\[x ^ 4 - y ^ 4
\]
再结合题目中所有元素互不相同,原式 \((a_i + a_j)(a_i ^ 2 + a_j ^ 2)\equiv k\pmod p\) 可以通过两边同乘非 \(0\) 的 \((a_i - a_j)\) 而改写为:
\[a_i ^ 4 - a_j ^ 4\equiv k(a_i - a_j) \pmod p
\]
整理得:
\[a_i ^ 4 - ka_i \equiv a_j^4 - ka_j \pmod p
\]
开一个 map 统计每个 \(a_i^4 - ka_i\) 的出现次数即可。
时间复杂度 \(O(n\log n)\)。
代码
值得一提的是,答案上界并不会爆 int,这与模质数意义下 \(4\) 次同余方程根的个数有关,读者可以自行去了解原理。
/*
*/
#include <bits/stdc++.h>
#define eps 0.0000000001
#define ls(x) ((x) << 1)
#define rs(x) (((x) << 1) | 1)
#define mid ((l + r) >> 1)
using namespace std;
typedef long long ll;
typedef unsigned ui;
typedef pair<ll, ll> pii;
const int N = 3e5 + 5, M = 20, P = 450, mod = 1e9 + 7, mod2 = 1e9 + 7, b1 = 131;
int a[N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int n,p,k;
cin>>n>>p>>k;
map<int,int> mp;
int res = 0;
for(int i=1;i<=n;i++){
cin>>a[i];
int x = (1ll * a[i] * a[i] % p * a[i] % p * a[i] % p + p - 1ll * k * a[i] % p) % p;
res += mp[x];
mp[x]++;
}
cout<<res;
return 0;
}

浙公网安备 33010602011771号