HDU 6128(乱搞)
来源:互联网 发布:手机服务器端口怎么查 编辑:程序博客网 时间:2024/04/29 03:56
Problem Description
There are n nonnegative integers a1…n which are less than p . HazelFan wants to know how many pairs i,j(1≤i<j≤n) are there, satisfying 1ai+aj≡1ai+1aj when we calculate module p , which means the inverse element of their sum equals the sum of their inverse elements. Notice that zero element has no inverse element.
Input
The first line contains a positive integer T(1≤T≤5) , denoting the number of test cases.
For each test case:
The first line contains two positive integersn,p(1≤n≤105,2≤p≤1018) , and it is guaranteed that p is a prime number.
The second line containsn nonnegative integers a1...n(0≤ai<p) .
For each test case:
The first line contains two positive integers
The second line contains
Output
For each test case:
A single line contains a nonnegative integer, denoting the answer.
A single line contains a nonnegative integer, denoting the answer.
Sample Input
25 71 2 3 4 56 71 2 3 4 5 6
Sample Output
46这个题题意是求使得 (ai+aj) 在模 p 下的逆元等于 ai 在模 p 下的逆元加上 aj 在模 p 下的逆元的 i j 的对数( i<j )式子两边同乘( ai + aj )*ai*aj 得 ai*aj=ai*(ai+aj)+aj*(ai+aj) (mod p).化简: ai*aj=ai^2 + aj^2 + 2*ai*aj (mod p)0=ai^2 + aj^2 + ai*aj (mod p)这个时候就可以用二次剩余搞了,但是我实在太弱,不会二次剩余,详情请百度大佬的做法但是还有另外一个神奇的算法:两边同乘 (ai-aj)然后就变成了:0=ai^3-aj^3 (mod p)令 bi=ai^3 (mod p), 找多少对 bi==bj然后就好说了不过要注意几点:①ai=0时是没有逆元的直接continue②当 ai==aj 时,会有ai-aj=0,所以在乘以 ai-aj 之前要判断 ai^2+aj^2+ai*aj 是否等于0,不等于0的话你乘了 ai-aj 也没用③p=3 时要单独特判,因为 p=3 时 ai 无非就等于 0 1 2 这三个,其中 0 直接continue,aj=ai时它们不管等于1还是2,ai^2+aj^2+ai*aj 模 p 都等于0,ai不等于aj时不管怎样目标式子模p都不等于0,与p取其他值的情况略有不同④这个方法并不优,只是好写而已,所以写法一定要优美,能省的计算就省,不然会TLE,我用不怎么优美的同一段代码交了几次才AC了两三次,2800ms,2900ms这样子,其他的都T了⑤在计算 ai*aj 的时候因为结果会炸 long long 所以要用快速乘法代码:#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <vector>#include <queue>#include <stack>#include <cstdlib>#include <cmath>#include <map>#include <string>using namespace std;typedef long long LL;const int MOD=1e9+7;map<LL,LL>s,t;LL n,p;LL mul(LL a,LL b){ LL ans=0; a=a%p; b=b%p; while(b>0) { if(b&1) ans=(ans+a)%p; a=(a+a)%p; b>>=1; } return ans;}LL a[200000+3];LL b[200000+3];LL c[200000+3];int main(){ int T; scanf("%d",&T); while(T--) { s.clear(); t.clear(); scanf("%lld%lld",&n,&p); if(p==3) { LL a1=0,a2=0,a3=0; for(int i=0;i<n;i++) { LL x; scanf("%lld",&x); if(x==1)a1++; else if(x==2)a2++; } printf("%lld\n",a1*(a1-1)/2+a2*(a2-1)/2); continue; } for(int i=0;i<n;i++) { scanf("%lld",&a[i]); if(a[i]==0)continue; LL y=mul(a[i],a[i]); LL z=mul(a[i],y);//ai==aj时ai^2 + aj^2 + ai*aj就成了 3 * ai^2 嘛 b[i]=z; c[i]=mul(3,y); s[z]++; t[a[i]]++; } /* for(int i=0;i<n;i++) { scanf("%lld",&a[i]); if(a[i]==0)continue; LL z=mul(a[i],mul(a[i],a[i])); b[i]=z; c[i]=mul(3,mul(a[i],a[i])); s[z]++; t[a[i]]++; } 之前交了好几发的同一段代码用的是这个,同一个快速乘算了两次,导致交几发才玄学过一发,其他的都T了,有兴趣的可以玩一下 */ LL ans=0; for(int i=0;i<n;i++) { if(a[i]==0)continue; { LL z=0; if(c[i]==0)//ai==aj时判断ai^2 + aj^2 + ai*aj为等于0的话不用减掉ai==aj的情况,直接算ai^3==aj^3即可 { z=s[b[i]]-1;//减掉ai它自己 } else//ai==aj时判断ai^2 + aj^2 + ai*aj为不等于0的话要减掉ai==aj的情况再算ai^3==aj^3 { z=s[b[i]]-t[a[i]]; } ans+=z; } } ans/=2; printf("%lld\n",ans); } return 0;}
emmmm........大概就这样了
本人蒟蒻,如有错误,还望指正
阅读全文
0 0
- HDU 6128(乱搞)
- HDU 5042 分段乱搞
- hdu 5211 Mutiple (乱搞)
- HDU 3536 乱搞
- HDU 5288 乱搞
- HDU 5349 乱搞
- HDU 5373 乱搞
- HDU 5301 Buildings (乱搞)
- HDU 5387 乱搞
- HDU 3600 乱搞
- HDU 5778 乱搞
- HDU 5831 乱搞
- HDU 5821 乱搞
- HDU Median (乱搞)
- HDU 5881 乱搞
- HDU 2340 Obfuscation 乱搞
- HDU 6161 乱搞+dp
- Hdu 6229 map乱搞
- 安装Ubuntu16.04,安装sogoupiyin for linux
- 用数组中的元素拼接出最小的数
- java之jdbc(mysql)
- PAT (Basic Level) Practise (中文) 1042. 字符统计(20)
- JPA 映射中 schema 属性的作用
- HDU 6128(乱搞)
- 两个集合取并集
- PWM控制小船
- 注入小结
- JavaSwing实现完整的菜单栏、工具栏和状态栏的GUI窗口
- 虚拟软件VMware
- js实现省市区三级联动
- uva 11987 并查集
- 再起航,我的学习笔记之JavaScript设计模式17(模板方法模式)