Description
给
n
个小于
Input
第一行一整数
T
表示用例组数,每组用例首先输入一整数
Output
输出满足条件的 (i,j)(1≤i<j≤n) 对数
Sample Input
2
5 7
1 2 3 4 5
6 7
1 2 3 4 5 6
Sample Output
4
6
Solution1
对 1ai+aj≡1ai+1aj 通分得 a2i+aiaj+a2j≡0
若 ai≠aj,a3i−a3j≡(ai−aj)(a2i+aiaj+a2j)≡0 ,用一个 map 存所有的 a3i%p 的值,另一个 map 存所有 ai 的值( ai≠0 ),在第一个 map 里计数,在第二个 map 里减掉 ai=aj 的情况即可
若 ai=aj ,由 12ai≡2ai 得 3ai≡0 ,注意到 0≤ai<p ,故只有 p=3 时 ai=aj 对答案有贡献,故在上述的计数过程中特判 p=3 的情况即可
Code1
#include<cstdio>
#include<map>
using namespace std;
typedef long long ll;
ll mod_mul(ll a,ll b,ll p)
{
ll ans=0;
while(b)
{
if(b&1)ans=(ans+a)%p;
a=(a+a)%p;
b>>=1;
}
return ans;
}
int T,n;
ll p;
map<ll,int>a,m;
map<ll,int>::iterator it;
ll C(int n)
{
return (ll)n*(n-1)/2;
}
int main()
{
scanf("%d",&T);
while(T--)
{
a.clear(),m.clear();
scanf("%d%I64d",&n,&p);
for(int i=1;i<=n;i++)
{
ll t;
scanf("%I64d",&t);
if(t)
{
a[t]++;
t=mod_mul(mod_mul(t,t,p),t,p);
m[t]++;
}
}
ll ans=0;
for(it=m.begin();it!=m.end();it++)
ans+=C(it->second);
if(p>3)
for(it=a.begin();it!=a.end();it++)
ans-=C(it->second);
printf("%I64d\n",ans);
}
return 0;
}
Solution2
对 1ai+aj≡1ai+1aj 通分得 a2i+aiaj+a2j≡0 ,进一步有 (aiaj)2+aiaj+1≡0 ,解此方程有 aiaj≡1±−3√2
故问题转化为
p−3
是否是模
p
二次剩余(
枚举 aj ,满足条件的 ai 是 aj×d ,拿 map 存 ai 每次计数累加答案即可
注意到如果 d=1 说明 ai=aj 也对答案有贡献,但在计数的时候会把 ai=ai 也算进去,所以要从答案中去掉这些不合法方案,即减掉 ai≠0 的个数
同时注意到,若 d2≡1 ,对于一对合法解 (ai,aj) ,在计算 ai 和 aj 的时候都被累加到答案中,故此时答案要除二
Code2
#include<cstdio>
#include<cstdlib>
#include<map>
#include<ctime>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
namespace fastIO
{
#define BUF_SIZE 100000
//fread -> read
bool IOerror=0;
inline char nc()
{
static char buf[BUF_SIZE],*p1=buf+BUF_SIZE,*pend=buf+BUF_SIZE;
if(p1==pend)
{
p1=buf;
pend=buf+fread(buf,1,BUF_SIZE,stdin);
if(pend==p1)
{
IOerror=1;
return -1;
}
}
return *p1++;
}
inline bool blank(char ch)
{
return ch==' '||ch=='\n'||ch=='\r'||ch=='\t';
}
inline void read(int &x)
{
char ch;
while(blank(ch=nc()));
if(IOerror)return;
for(x=ch-'0';(ch=nc())>='0'&&ch<='9';x=x*10+ch-'0');
}
inline void readlld(ll &x)
{
char ch;
while(blank(ch=nc()));
if(IOerror)return;
for(x=ch-'0';(ch=nc())>='0'&&ch<='9';x=x*10ll+ch-'0');
}
inline void readc(char &x)
{
char ch;
while(blank(ch=nc()));
if(IOerror)return;
x=ch;
}
inline void reads(char *x)
{
char ch;
while(blank(ch=nc()));
if(IOerror)return;
int n=0;
while(1)
{
x[n++]=ch;
if(blank(ch=nc()))break;
}
x[n]='\0';
}
#undef BUF_SIZE
};
using namespace fastIO;
#define maxn 100005
ull Rand()
{
ull a=rand(),b=rand(),c=rand(),d=rand();
return a*b*c*d;
}
typedef long long ll;
typedef long double ld;
ll Mul(ll a,ll b,ll p)
{
return (a*b-(ll)(a/(ld)p*b+1e-3)*p+p)%p;
}
ll Pow(ll a,ll b,ll p)
{
ll ans=1;;
while(b)
{
if(b&1)ans=Mul(ans,a,p);
a=Mul(a,a,p);
b>>=1;
}
return ans;
}
//表示x+y*sqrt(w)
struct T
{
ll x,y;
T(){};
T(ll _x,ll _y){x=_x,y=_y;}
};
ll w;
T T_Mul(T a,T b,ll p)
{
T ans;
ans.x=(Mul(a.x,b.x,p)+Mul(Mul(a.y,b.y,p),w,p))%p;
ans.y=(Mul(a.x,b.y,p)+Mul(a.y,b.x,p))%p;
return ans;
}
T T_Pow(T a,ll b,ll p)
{
T ans=T(1,0);
while(b)
{
if(b&1)ans=T_Mul(ans,a,p);
a=T_Mul(a,a,p);
b>>=1;
}
return ans;
}
ll Solve(ll a,ll p)//求解x^2=a(mod p)
{
a%=p;
if(!a)return 0;
if(p==2)return 1;
if(Pow(a,(p-1)/2,p)==p-1)return -1;
ll b;
while(1)
{
b=Rand()%p;
w=(Mul(b,b,p)-a+p)%p;
if(Pow(w,(p-1)/2,p)==p-1)break;
}
T ans=(T){b,1};
ans=T_Pow(ans,(p+1)/2,p);
return ans.x;
//另一个解为p-ans.x
}
int Case,n;
ll a[maxn],p;
map<ll,int>m;
int main()
{
srand(time(0));
//freopen("1009.in","r",stdin);
read(Case);
//scanf("%d",&Case);
while(Case--)
{
m.clear();
//scanf("%d%I64d",&n,&p);
read(n),readlld(p);
int num=0;
for(int i=1;i<=n;i++)
{
readlld(a[i]);
//scanf("%I64d",&a[i]);
if(a[i])num++,m[a[i]]++;
}
ll d=Solve(p-3,p);
if(p==2||d==-1)
{
printf("0\n");
continue;
}
if(d&1)d=(d-1)>>1;
else d=(d-1+p)>>1;
ll ans=0;
for(int i=1;i<=n;i++)ans+=m[Mul(a[i],d,p)];
if(d==1)ans-=num;
if(Mul(d,d,p)==1)ans/=2;
printf("%d\n",ans);
}
}