部分引用自:http://blog.csdn.net/v5zsq/article/details/77255048

所以假设方程 x^2+x+1=0 在模p意义下的解为d,则答案就是满足(ai/aj) mod p = d的数对(i,j)的数量(i<j)。

现在把问题转化为解这个模意义下的二次方程。

x^2+x+1=0

配方:x^2+x+1/4+3/4=0

(x+1/2)^2+3/4=0

同乘4:(2x+1)^2+3=0

即(2x+1)^2=-3 (mod p)

换句话说,我们必须保证-3+p是p的一个二次剩余

倘若-3+p不是p的一个二次剩余的话,无解。

如果是的话,我们就可以通过Cipolla算法得到2x+1的两个可能值,也就把二次同余方程变成了两个线性同余方程。

然后在一般情况下可以通过扩展欧几里得算法求得这两个个线性同余方程的最小非负整数解,也就得到了这个二次同余方程的两个解。

不过这题的情况有点特别,形式非常简单,根据大神的总结,在我们得到2x+1的两个值d1、d2之后,可以这样得到x1、x2。

于是我们可以通过枚举+map来得到点对的个数。

注意特殊情况:①倘若x1或者x2为零的话,意味着(ai/aj)mod p=0,这是不可能的,注意不要统计这种。

②p为2时无解。

③p为3时有解,但是由于p-3等于零,所以不能直接用上面的方法。不过经过简单的推导,我们发现唯一合法的情况是ai=aj,且ai、aj均不为零,直接特判掉。

求解二次剩余的Cipolla算法:

http://blog.csdn.net/a_crazy_czy/article/details/51959546

http://blog.csdn.net/philipsweng/article/details/50000903

一句话:通过勒让德符号来判断n是不是模p的二次剩余,然后random一个a,使得(a^2-n)不是二次剩余,然后通过复数快速幂来求二次剩余的值。

#include<cstdio>
#include<map>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
ll p,a[200005];
struct Complex{
ll a,b;
Complex(const ll &a,const ll &b){
this->a=a;
this->b=b;
}
Complex(){}
};
map<ll,int>ma;
int T,n;
ll Quick_Mul(ll x,ll p,ll mod){
if(!p){
return 0ll;
}
ll res=Quick_Mul(x,p>>1,mod);
res=(res+res)%mod;
if((p&1ll)==1ll){
res=(x%mod+res)%mod;
}
return res;
}
ll Quick_Pow(ll x,ll p,ll mod){
if(!p){
return 1ll;
}
ll res=Quick_Pow(x,p>>1,mod);
res=Quick_Mul(res,res,mod);
if((p&1ll)==1ll){
res=Quick_Mul(x%mod,res,mod);
}
return res;
}
ll aa,nn;
Complex Complex_Mul(const Complex &A,const Complex &B,const ll &p){
return Complex((Quick_Mul(A.a,B.a,p)+Quick_Mul(Quick_Mul(A.b,B.b,p),(Quick_Mul(aa,aa,p)-nn+p)%p,p))%p,
(Quick_Mul(A.a,B.b,p)+Quick_Mul(A.b,B.a,p))%p);
}
Complex Complex_Quick_Pow(Complex x,ll p,ll mod){
if(!p){
return Complex(1ll,0ll);
}
Complex res=Complex_Quick_Pow(x,p>>1,mod);
res=Complex_Mul(res,res,mod);
if((p&1ll)==1ll){
res=Complex_Mul(x,res,mod);
}
return res;
}
ll ran1(){
return ((rand()<<16)|rand());
}
ll ran(){
return ((ran1()<<16)|ran1());
}
pair<ll,ll> work(ll n,ll p){
aa=ran()%p;
nn=n;
while(Quick_Pow((Quick_Mul(aa,aa,p)-n+p)%p,(p-1ll)/2ll,p)!=p-1ll){
aa=ran()%p;
}
ll res=Complex_Quick_Pow(Complex(aa,1ll),(p+1ll)/2ll,p).a;
return make_pair(res,p-res);
}
ll ans;
ll f(ll x,ll p){
return (x&1ll)==1ll ? (x-1ll)/2ll : (x-1ll+p)/2ll;
}
int main(){
// freopen("1009.in","r",stdin);
// freopen("hdu6128.out","w",stdout);
srand(233);
scanf("%d",&T);
for(;T;--T){
ans=0;
ma.clear();
scanf("%d%lld",&n,&p);
for(int i=1;i<=n;++i){
scanf("%lld",&a[i]);
}
if(p==2ll || Quick_Pow(p-3ll,(p-1ll)/2ll,p)==p-1ll){
puts("0");
continue;
}
if(p==3ll){
for(int i=1;i<=n;++i){
if(a[i]){
ans+=ma[a[i]];
}
++ma[a[i]];
}
printf("%lld\n",ans);
continue;
}
pair<ll,ll> d=work(p-3ll,p);
d.first=f(d.first,p);
d.second=f(d.second,p);
for(int i=1;i<=n;++i){
if(d.first){
ans+=ma[Quick_Mul(a[i],d.first%p,p)];
}
if(d.second){
ans+=ma[Quick_Mul(a[i],d.second%p,p)];
}
if(a[i]){
++ma[a[i]];
}
}
printf("%lld\n",ans);
}
return 0;
}

【数论】【二次剩余】【map】hdu6128 Inverse of sum的更多相关文章

  1. 2017多校第7场 HDU 6128 Inverse of sum 推公式或者二次剩余

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6128 题意:给你n个数,问你有多少对i,j,满足i<j,并且1/(ai+aj)=1/ai+1/a ...

  2. 数学--数论--HDU 6128 Inverse of sum (公式推导论)

    Description 给nn个小于pp的非负整数a1,-,na1,-,n,问有多少对(i,j)(1≤i<j≤n)(i,j)(1≤i<j≤n)模pp在意义下满足1ai+aj≡1ai+1aj ...

  3. 2017ACM暑期多校联合训练 - Team 7 1009 HDU 6128 Inverse of sum (数学计算)

    题目链接 Problem Description There are n nonnegative integers a1-n which are less than p. HazelFan wants ...

  4. [zoj 3774]Power of Fibonacci 数论(二次剩余 拓展欧几里得 等比数列求和)

    Power of Fibonacci Time Limit: 5 Seconds      Memory Limit: 65536 KB In mathematics, Fibonacci numbe ...

  5. HDU 6128 Inverse of sum(同余)

    http://acm.hdu.edu.cn/showproblem.php?pid=6128 题意:有一个a数列,并且每个数都小于p,现在要求有多少对$(i,j)$满足$\frac{1}{a_i+a_ ...

  6. apache_commons 之 双向Map DualHashBidiMap (使用及源码)

    在项目当中,经常出现需要根据Key值获取value:而且要求根据value获取key值,其实在commons-collections包中已经提供了此集合类.就是DualHashBidiMap类. (官 ...

  7. Leetcode: Path Sum III

    You are given a binary tree in which each node contains an integer value. Find the number of paths t ...

  8. 325. Maximum Size Subarray Sum Equals k

    最后更新 二刷 木有头绪啊.. 看答案明白了. 用的是two sum的思路. 比如最终找到一个区间,[i,j]满足sum = k,这个去见可以看做是 [0,j]的sum 减去 [0,i]的Sum. 维 ...

  9. [leetcode-508-Most Frequent Subtree Sum]

    Given the root of a tree, you are asked to find the most frequent subtree sum. The subtree sum of a ...

随机推荐

  1. 如何彻底关闭退出vmware虚拟机

    如何彻底关闭退出vmware虚拟机 每次使用虚拟机之后退出时,它都会在系统托盘区留下一个虚拟机图标,该如何彻底关闭退出vmware虚拟机呢? 首先我们需要运行一下虚拟机程序 1:我们如果要对虚拟机进行 ...

  2. bzoj 1058 bst

    因为是数列的维护,所以我们可以考虑用splay来维护,每次在x插入的时候就在x+1前面插入就行了,然后用bst来维护两问的答案,但是应该会tle.我们来考虑这个问题的性质,首先因为这个数列没有删除操作 ...

  3. 2017-3-26 webpack入门(一)

    2017-3-26 webpack入门(一) webpack 前端 打包 最近项目里用到了webpack特意总结一下.来源:http://webpackdoc.com 1 概念 1.1 webpack ...

  4. hdu 4190 Distributing Ballot Boxes(贪心+二分查找)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4190 Distributing Ballot Boxes Time Limit: 20000/1000 ...

  5. charger related source code position

    Platform Qualcomm MSM8917 or MSM8937 Source kernel/msm-3.18/drivers/power/qpnp-smbcharger.c kernel/m ...

  6. 2017多校第8场 HDU 6133 Army Formations 线段树合并

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6133 题意:给你一棵n个节点的二叉树,每个节点有一个提交任务的时间,每个节点总的提交任务的罚时为:提交 ...

  7. [PAT] 1146 Topological Order(25 分)

    This is a problem given in the Graduate Entrance Exam in 2018: Which of the following is NOT a topol ...

  8. LeetCode解题报告—— Trapping Rain Water

    Given n non-negative integers representing an elevation map where the width of each bar is 1, comput ...

  9. CentOS7.5安装坚果云

    1.下载坚果云rpm包,对于CentOS,选fedora那个版本的包 https://www.jianguoyun.com/s/downloads/linux 2.安装 坚果云安装依赖notify-p ...

  10. hdu 1556 Color the ball(线段树区间维护+单点求值)

    传送门:Color the ball Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/3276 ...