HDU 6128 Inverse of sum(推公式)

本文介绍了一种算法,用于解决特定的数学问题:给定一个整数序列和一个质数p,找出序列中所有满足特定模逆数性质的数对。通过巧妙地变换等式并使用哈希表优化搜索过程,该算法能够在合理的时间内解决问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Inverse of sum

Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others)
Total Submission(s): 657 Accepted Submission(s): 223

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 integers n,p(1≤n≤105,2≤p≤1018), and it is guaranteed that p is a prime number.
The second line contains n nonnegative integers a1…n(0≤ai<p).

Output
For each test case:
A single line contains a nonnegative integer, denoting the answer.

Sample Input
2
5 7
1 2 3 4 5
6 7
1 2 3 4 5 6

Sample Output
4
6

题意

一个长度为n的序列,问其中有几对1ai+aj≡1ai+1aj\frac{1}{a_{i}+a_{j}}\equiv \frac{1}{a_{i}}+\frac{1}{a_{j}}ai+aj1ai1+aj1(mod p)

思路

1ai+aj≡1ai+1aj\frac{1}{a_{i}+a_{j}}\equiv \frac{1}{a_{i}}+\frac{1}{a_{j}}ai+aj1ai1+aj1*(mod p)两边同乘ai+aja_{i}+a_{j}ai+aj
1≡1+ajai+1+aiaj1 \equiv 1+\frac{a_{j}}{a_{i}}+1+\frac{a_{i}}{a_{j}}11+aiaj+1+ajai
(mod p)再同乘aiaja_{i}a_{j}aiaj
ai2+aiaj+aj2≡0a_{i}^{2}+a_{i}a_{j}+a_{j}^{2}\equiv 0ai2+aiaj+aj20
(mod p)*再同乘ai−aja_{i}-a_{j}aiaj

ai3−aj3≡0a_{i}^{3}-a_{j}^{3}\equiv 0ai3aj30(mod p)
然后我们枚举ai3a_{i}^{3}ai3%p用map来储存
值得注意的是当ai==aja_{i}==a_{j}ai==ajai2+aiaj+aj2≡0a_{i}^{2}+a_{i}a_{j}+a_{j}^{2}\equiv 0ai2+aiaj+aj20就变为3ai2≡03a_{i}^{2}\equiv 03ai20,而此时若ai2+aiaj+aj2≡0a_{i}^{2}+a_{i}a_{j}+a_{j}^{2}\equiv 0ai2+aiaj+aj20不成立而还是乘上了一个ai−aja_{i}-a_{j}aiaj,那么我们把这个时候的ai3a_{i}^{3}ai3%p算出来也无用,所以要去掉当ai2+aiaj+aj2≡0a_{i}^{2}+a_{i}a_{j}+a_{j}^{2}\equiv 0ai2+aiaj+aj20不成立的时候的aia_{i}ai3ai2≡03a_{i}^{2}\equiv 03ai20不成立的情况

#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <map>
using namespace std;
map<long long,int>num;
map<long long,int>cnt;
long long multi(long long a,long long b,long long p){
    long long ans=0;
    while(b){
        if(b%2==1)
            ans=(ans+a)%p;
        b/=2;
        a=(a+a)%p;
    }
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        long long n,p;
        scanf("%lld%lld",&n,&p);
        cnt.clear();
        num.clear();
        long long ans=0;
        for(int i=0;i<n;i++)
        {
            long long a;
            scanf("%lld",&a);
            if(a==0)
                continue;
            if(multi(multi(a,a,p),3,p)!=0)
                ans-=cnt[a];
            cnt[a]++;
            long long val=multi(multi(a,a,p),a,p);
            ans+=num[val]++;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值