*题解: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;
}
posted @ 2026-08-03 18:55  yutar  阅读(3)  评论(0)    收藏  举报