HDU 6128-数论

Posted 水明

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 6128-数论相关的知识,希望对你有一定的参考价值。

题意&官方题解

没学过二次剩余……比赛的时候想到了下面的方法(1591ms)。但是没特判$p=3$的情况,愉快的WA……

 

分析

根据式子我们可以推到$a^2+ab+b^2=0 (mod\\ p)$

 

当$a=b$的时候

$3a^2=0(mod\\ p)$

当$p=3$的时候有解$a=1\\ or\\ a=2$

当$p \\neq 3$的时候无解

 

当$a \\neq b$的时候

不妨两边乘$(a-b)$得到$a^3-b^3=0 (mod\\ p)$

 就得到了散列函数$f(x)=x^3mod\\;p$

 

结论也就出现了

$\\begin{cases}a=b=1\\ or\\ a=b=2,p=3 \\\\f(a)=f(b),p \\neq 3 \\end{cases}$

注意数据范围,最大有$10^{18}$,立方的时候需要快速乘

具体分析

样例1

6 3

0 1 1 2 2 2

- 1 1 2 2 2 逆元

- 1 1 2 2 2 $f(x)$

4

解集为$\\{(1,1),(2,2),(2,2),(2,2)\\}$

样例1

5 7

1 2 3 4 5 6

1 4 5 2 3 6 逆元

1 1 6 1 6 6 $f(x)$

6

解集为$\\{(1,2),(1,4),(2,4),(3,5),(3,6),(5,6)\\}$,都满足$f(a)=f(b),a \\neq b$

样例3

5 7

1 1 2 2 4

1 1 4 4 2

1 1 1 1 1 $f(x)$

8

解集为$\\{(1,2),(1,2),(1,4),(1,2),(1,2),(1,4),(2,4),(2,4)\\}$,都满足$f(a)=f(b),a \\neq b$

代码

#include <map>
#include <set>
#include <queue>
#include <cmath>
#include <ctime>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define MAX     1000007
#define MAXN      10007
#define MAXM      20007
#define INF  0x3f3f3f3f
#define NINF 0xc0c0c0c0
#define MOD  1000000007
using namespace std;
typedef unsigned long long LL;


LL a[MAX],p;
int n;
LL Multi(LL a,LL b,LL m){
    LL ret = 0;  
    while(b){  
        if(b&1) ret=(ret+a)%m;  
        b>>= 1;  
        a=(a<<1)%m;  
    }  
    return ret;  
}  
LL ac(LL x){
    return (x-1)*x/2;
}
map<LL,map<LL,LL> >M;
map<LL,LL>sum;
LL x;
int main(){
    int cas;
    scanf("%d",&cas);
    while(cas--){
        M.clear();
        sum.clear();
        scanf("%d%lld",&n,&p);
        if(p==3){
            int xx,one=0,two=0;
            for(int i=0;i<n;i++){
                scanf("%d",&xx);
                if(xx==1)one++;
                else if(xx==2)two++;
            }
            printf("%d\\n",ac(one)+ac(two));
            continue;
        }
        LL num=0;
        for(int i=0;i<n;i++){
            scanf("%lld",&x);
            x%=p;
            if(x==0)continue;
            LL y=Multi(x,x,p);
            y=Multi(x,y,p);
            M[y][x]++;
            sum[y]++;
            num++;
        }
        LL ans=0;
        map<LL,map<LL,LL> >::iterator it=M.begin();
        for(;it!=M.end();it++){
            //printf("%lld\\n", it->first);
            if(it->first==0)continue;
            ans+=ac(sum[it->first]);
            //printf("%lld %lld\\n",sum[it->first],ans);
            map<LL,LL>::iterator tt=it->second.begin();
            for(;tt!=it->second.end();tt++){
                ans-=ac(tt->second);
            }
        }
        printf("%lld\\n",ans);
    }
    return 0;
}

  

以上是关于HDU 6128-数论的主要内容,如果未能解决你的问题,请参考以下文章

HDU6128 二次剩余/二次域求二次剩余解/LL快速乘法取模

数论专题hdu2582

数论专题hdu2674

数论专题hdu2197

数论专题hdu2104

数论——HDU - 2136