解题报告:HDU_6128:Inverse of sum (二次剩余)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_32570675/article/details/77371662

题目链接

题意及官方题解:



思路:

已知公式:

转换一下:

对于每个y,满足要求的x为:

只需要求的y的系数在(%mod)意义下的等价式即可

等同于求sqrt(-3)的等价式,也就是求p-3在(%mod)意义下的二次剩余( Cipolla's algorithm )

注意一些细节:不考虑0、mod=2、mod=3、x==y时的计数 、 不存在p-3的二次剩余 以及 用防溢出的超级快速幂


代码:

#include<bits/stdc++.h>

#define LL long long
#define pll pair<LL,LL>
#define fi first
#define se second

const int N = 1e5+10;
using namespace std;

inline LL fast_mul(LL x,LL y,LL mod){
    LL res = 0;
    if(x>=mod)x-=mod;
    while(y){
        if(y&1){
            res += x;
            while(res>=mod)res -= mod;
        }y>>=1;x<<=1;
        while(x>=mod)x -= mod;
    }
    return res;
}
inline LL fast_pow(LL x,LL y,LL mod){
    LL res = 1;
    while(y){
        if(y&1)res = fast_mul(res,x,mod);
        y>>=1;x = fast_mul(x,x,mod);
    }
    return res;
}
pll multi_er(pll a,pll b,LL mod,LL w){
   pll res ;
   res.fi = fast_mul(a.fi,b.fi,mod)+fast_mul(fast_mul(a.se,b.se,mod),w,mod);
   if(res.fi>=mod)res.fi-=mod;
   res.se = fast_mul(a.fi,b.se,mod)+fast_mul(a.se,b.fi,mod);
   if(res.se>=mod)res.se-=mod;
   return res;
}

pll qmlti_er(pll x,LL y,LL mod,LL w){
   pll res(1,0);
   while(y){
      if(y&1)res = multi_er(res,x,mod,w);
      y>>=1;x = multi_er(x,x,mod,w);
   }return res;
}

LL Rand(LL mod){
   LL res = 0,k=1;
   while(mod){
      res = res + k * (rand()%(mod%10+1));
      k *= 10;
      mod/=10;
   }
   return res;
}

LL work(LL x,LL mod){
   if(mod==2)return 1;
   LL a,w;
   do{
      a = Rand(mod);
      if(a==0||a==mod)continue;
      w=fast_mul(a,a,mod)-x;
      if(w<0)w+=mod;
   }while(fast_pow(w,(mod-1)>>1,mod)==1);
   pll res(a,1);
   res = qmlti_er(res,(mod+1)>>1,mod,w);
   return res.fi;
}
map<LL,int>M;
LL A[N];

int main()
{
   //freopen("1009.in","r",stdin);
   //freopen("my_1009.out","w",stdout);
   srand(time(0));
   int T;
   scanf("%d",&T);
   while(T--){
      M.clear();int n;
      LL x,ni,a,b,mod;
      bool ok = true;
      scanf("%d%lld",&n,&mod);
      if(fast_pow(mod-3,(mod-1)>>1,mod)!=1||mod<=3)ok = false;
      else {
         ni = work(mod-3,mod);
         if((a=ni-1)&1)a+=mod;a>>=1;
         if((b=mod-1-ni)&1)b+=mod;b>>=1;
      }long long ans = 0;
      for(int i=0;i<n;i++){
         scanf("%lld",&A[i]);
         if(!A[i])continue;
         if(mod==3LL)ans+=M[A[i]]++;
         else ++M[A[i]];
      }if(mod<=3||!ok){
         printf("%lld\n",ans);
         continue;
      }
      for(int i=0;i<n;i++){
         x = A[i];
         if(!x)continue;
         LL tmp = fast_mul(x,a,mod);
         auto it = M.find(tmp);
         if(it!=M.end())ans+=(it->se);
         if(tmp==x)ans--;
         tmp = fast_mul(x,b,mod);
         it = M.find(tmp);
         if(it!=M.end())ans+=(it->se);
         if(tmp==x)ans--;
      }printf("%lld\n",ans/2);
   }return 0;
}




阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页