2017多校第7场 HDU 6128 Inverse of sum 推公式或者二次剩余

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6128

题意:给你n个数,问你有多少对i,j,满足i<j,并且1/(ai+aj)=1/ai+1/a在%p意义下。

解法:官方题解说是用二次剩余来解,但是我并不会这玩意了。在网上看到一位大佬没有二次剩余直接通过推公式做出了这题,真是神奇。http://www.cnblogs.com/bin-gege/p/7367337.html  将式子通分化简后可得(ai2+aj2+ai*aj)%p=0 。然后两边同时将两边乘(ai-aj),化简可得(ai3-aj3)%p=0。那么直接计算满足这个等式的pair的对数就可以了吗?不是。我们还要考虑到a[i]=a[j]的时候,也就是a[i]*a[i]+a[i]*a[i]+a[i]*a[i]=0modp是不满足条件的,但是我们直接计算上面那个式子会把满足这个关系的式子也算进去,所以我们需要把满足a[i]=a[j]并且3*a[i]*a[j]>0的这些对数减掉。我这个代码跑了2900多ms,所以这题还是顶二次剩余吧。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5+4;
int T,n;
LL p,a[maxn];
map<LL,int>cnt;
map<LL,int>cnt2;
inline LL quick_mul(LL a,LL n,LL m)
{
    LL ans=0;
    while(n)
    {
        if(n&1) ans=(ans+a)%m;
        a=(a+a)%m;
        n>>=1;
    }
    return ans;
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%lld", &n,&p);
        for(int i=1; i<=n; i++) scanf("%lld", &a[i]);
        LL ans=0;
        cnt.clear();
        cnt2.clear();
        for(int i=1; i<=n; i++){
            if(!a[i]) continue;
            if(quick_mul(3,quick_mul(a[i],a[i],p),p)) ans-=cnt2[a[i]];
            LL t = quick_mul(quick_mul(a[i],a[i],p),a[i],p);
            ans += cnt[t];
            cnt[t]++;
            cnt2[a[i]]++;
        }
        printf("%lld\n", ans);
    }
    return 0;
}
时间: 2024-08-27 11:05:15

2017多校第7场 HDU 6128 Inverse of sum 推公式或者二次剩余的相关文章

hdu 6128 Inverse of sum(推公式)

题目链接:hdu 6128 Inverse of sum 题意: 给你n个数,问你有多少对i,j,满足i<j,并且1/(ai+aj)=1/ai+1/aj 在%p意义下. 题解: 不愧是高中生,推公式神题. 将式子通分化简后可得(ai2+aj2+ai*aj)%p=0. 然后两边同时将两边乘(ai-aj),化简可得(ai3-aj3)%p=0. 然后就可以用map记录一下个数,并且减掉ai==aj时不合法的情况就行了. 1 #include<bits/stdc++.h> 2 #define F

2017多校第8场 HDU 6143 Killer Names 容斥,组合计数

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6143 题意:m种颜色需要为两段长度为n的格子染色,且这两段之间不能出现相同的颜色,问总共有多少种情况. 解法:枚举要为这两段分配的颜色数目分别为 i,j ,则在第一段总共有 C(m,i) 种选取方案,在第二段总共有 C(m?i,j) 种选取方案.而在每段内部,我们设 F(n,x) 为长度为 n 的格子使用 x 种颜色(等于 x )染色的方案数.则根据容斥原理 F(n,x)=x^n?C(x,1)*(x

2017多校第4场 HDU 6078 Wavel Sequence DP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6078 题意:求两个序列的公共波形子序列的个数. 解法: 类似于最长公共上升子序列,对于每个i,只考虑存在j使得a[i]==b[j]的情况. dp[i][j][0]表示以a[i]和b[j]为公共序列结尾且为波谷的情况总和. dp[i][j][1]则表示波峰的情况总和. S[i][j][0]表示sum(dp[k][j][0] | 1<=k<=j-1). S[i][j][1]则表示sum(dp[k][j

2017多校第7场 HDU 6129 Just do it 找规律

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6129 题意:求a序列后m次xor前缀和 解法: 手动对1位置对每个位置的贡献打表发现 第一次 贡献为 1 1 1 1 1 1 1 1 1 1 1 第二次 贡献为 1 0 1 0 1 0 1 0 1 0 1 0 第四次 贡献为 1 3个0 1 3个0 1 3个0 1 3个0 第八次 贡献为 1 7个0 1 7个0 1 7个0 1 7个0 ... 这是比赛之后才知道的,看着比赛的时候通过了200+人,被

2017多校第10场 HDU 6180 Schedule 贪心,multiset

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6180 题意:给了一些任务的开始时间和终止时间,现在让我们安排k台及机器,让这些任务在k太机器上最小,并且使得机器的运行时间的和最小. 解法:按开始工作的时间从小到大排序后,用一个set容器维护一下,每次加入找set里面结束时间小于等于开始时间并且最近的点插入即可,然后如果没有小于开始时间的就重新开一台机器即可,这里可能有重复元素,需要multiset. #include <bits/stdc++.h

2017多校第9场 HDU 6170 Two strings DP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6170 题意:给了2个字符串,其中第2个字符串包含.和*两种特别字符,问第二个字符串能否和第一个匹配. 解法:dp[i][j]代表在第一个串的i位置,第2个串的j位置是否可以匹配,然后按照'*'这个特殊情况讨论转移即可. #include <bits/stdc++.h> using namespace std; const int maxn = 3005; bool dp[maxn][maxn];

2017多校第10场 HDU 6181 Two Paths 次短路

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6181 题意:给一个图,求出次短路. 解法:我之前的模板不能解决这种图,就是最短路和次短路相等的情况,证明这题数据还是水了.下来我修改了一下次短路的,就可以避免这种情况了.提供一个sample 4 4 (1,2,1)( 1, 3,1) (2 4,1) (3 ,4,1).这组的正确答案是2,算法就来看代码吧. #include <bits/stdc++.h> using namespace std;

2017多校第8场 HDU 6134 Battlestation Operational 莫比乌斯反演

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6134 题意: 解法: 那么g(n)怎么求,我们尝试打表发现g(n)是有规律的,g(n)=g(n-1)+d(n-1)+1,其中d(i)表示i的因子个数,这个我们是可以通过线性筛O(n)处理出来的,之后再O(n)维护g(i)的前缀和,就可以在单组sqrt(n)的复杂度下得到答案了. #include <bits/stdc++.h> using namespace std; typedef long l

2017多校第10场 HDU 6172 Array Challenge 猜公式,矩阵幂

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6172 题意:如题. 解法: #include <bits/stdc++.h> using namespace std; typedef long long LL; const LL mod = 1e9+7; struct Matrix{ LL a[3][3]; void set1(){ memset(a, 0, sizeof(a)); } void set2(){ memset(a, 0, siz