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-数论的主要内容,如果未能解决你的问题,请参考以下文章