I love permutation

博客探讨了在给定奇素数p和整数a下,生成序列A的逆序对对数模2的结果。通过数学证明,序列A是一个排列,并通过分析逆序对的奇偶性,利用扩展欧拉定理简化计算,最终确定逆序对数量的奇偶性。代码实现中涉及高精度快速幂运算,讨论了不同编程语言处理大数据的挑战。

题目链接

题意:给定一个奇素数 p p p和一个小于 p p p的整数 a a a,按如下规则生成一序列 A A A: A i = a ∗ i A_i = a*i%p Ai=ai, 1 1 1 ≤ \leq i i i < < < p p p,问A序列的逆序对对数模 2 2 2的结果

解析:
①可以证明A是一个又 1 1 1 ⋯ \cdots p − 1 p-1 p1构成的排列:不妨假定在取模后 A i = A j A_i=A_j Ai=Aj,且 i > j i>j i>j由定义有在取模之前 A i = k 1 ∗ p + c = a ∗ i A_i=k_1*p+c=a*i Ai=k1p+c=ai, A j = k 2 ∗ p + c = a ∗ j A_j=k_2*p+c=a*j Aj=k2p+c=aj,则 A i − B j = ( k 1 − k 2 ) ∗ p = a ∗ ( i − j ) A_i-B_j=(k_1-k_2)*p=a*(i-j) AiBj=(k1k2)p=a(ij),移项有 i − j = i-j= ij= ( k 1 − k 2 ) ∗ p a (k_1-k_2)*p \over a a(k1k2)p < p <p <p,由于 i − j i-j ij为整数且 a , p a,p a,p互质,所以 ( k 1 − k 2 ) a (k1-k2) \over a a(k1k2)为整数,由 ( k 1 − k 2 ) ∗ p a (k_1-k_2)*p \over a a(k1k2)p < p <p <p ( k 1 − k 2 ) a (k1-k2) \over a a(k1k2) ≤ \leq 1 1 1,若 ( k 1 − k 2 ) a (k1-k2) \over a a(k1k2) = 0 =0 =0,则有取模之前 A i = B j A_i=B_j Ai=Bj,与 a ∗ i a*i ai ≠ \neq = a ∗ j a*j aj矛盾,若 ( k 1 − k 2 ) a (k1-k2) \over a a(k1k2) = 1 =1 =1,则有 a ∗ i a*i ai ≥ \geq a ∗ p + c a*p+c ap+c,与 1 1 1 ≤ \leq i i i < < < p p p矛盾,故不存在取模后 A i = A j A_i=A_j Ai=Aj的情况
②当 i < j i<j i<j时,如果 A i , A j A_i,A_j Ai,Aj构成逆序对,则 ( A i − A j ) ( i − j ) (A_i-A_j) \over (i-j) (ij)(AiAj) < 0 <0 <0,反之 ( A i − A j ) ( i − j ) (A_i-A_j) \over (i-j) (ij)(AiAj) > 0 >0 0,所以判断一个序列中的逆序对对数的奇偶性只需要判断 ∏ 0 < i < j < p \prod_{0<i<j<p} 0<i<j<p ( A i − A j ) ( i − j ) (A_i-A_j) \over (i-j) (ij)(AiAj)的正负即可,当A是一个排列时, ∏ 0 < i < j < p \prod_{0<i<j<p} 0<i<j<p ( A i − A j ) ( i − j ) (A_i-A_j) \over (i-j) (ij)(AiAj) = ( − 1 ) x =(-1)^x =(1)x,因为 i , j 和 A i , A j i,j和A_i,A_j i,jAi,Aj都是从一个由 1 1 1 ⋯ \cdots p − 1 p-1 p1的排列中取数,所以 ∏ 0 < i < j < p \prod_{0<i<j<p} 0<i<j<p ( A i − A j ) (A_i-A_j) (AiAj) ∏ 0 < i < j < p \prod_{0<i<j<p} 0<i<j<p ( i − j ) (i-j) (ij)的绝对值是相等的
③带入题目A的定义式化简2中式子, ∏ 0 < i < j < p \prod_{0<i<j<p} 0<i<j<p ( A i − A j ) ( i − j ) (A_i-A_j) \over (i-j) (ij)(AiAj) = = = ∏ 0 < i < j < p \prod_{0<i<j<p} 0<i<j<p ( a ∗ i − a ∗ j ) ( i − j ) (a*i -a*j) \over (i-j) (ij)(aiaj) = = = ∏ 0 < i < j < p \prod_{0<i<j<p} 0<i<j<p i − j ( i − j ) i-j \over (i-j) (ij)ij ∗ a *a a = = = a p ∗ ( p − 1 ) 2 a^{p*(p-1) \over 2} a2p(p1),由扩展欧拉定理可化为 2 p − 1 2 2^{p-1 \over 2} 22p1(由于显示原因上述运算没加上取模),所以我们只需要判断 a p ∗ ( p − 1 ) 2 a^{p*(p-1) \over 2} a2p(p1)是否为1即可,若为1,则说明逆序对数为偶数个

吐槽一波数据范围真的毒,C++好像只能__int128过?(也可能我的高精太慢了?),好奇java选手怎么过的,试着写了一次java大数然后T了

AcCode:

#include<iostream>
#include<algorithm>
#include<string>
#include<cstring>
#include<vector>
#include<cstdio>

#define int long long
#define iter vector<int>::iterator

using namespace std;

const int base = 100000000;
const int N = 300;


int quick_pow(__int128 a, __int128 b, __int128 p)
{
	__int128 ans = 1;
	while (b)
	{
		if (b & 1)
			ans = ans * a % p;
		a = a * a % p;
		b >>= 1;
	}
	return ans;
}
inline int mul(int a, int b, int p) {
	int ans = 0;
	while (b) {
		if (b & 1) ans = ans + a % p;
		a = a + a % p;
		b >>= 1;
	}
	return ans;
}

signed main() {
	int t; scanf("%lld", &t);
	while (t--) {
		int a, p; scanf("%lld %lld", &a, &p);
		int pw = (p - 1) / 2;
		int ans = quick_pow(a, pw, p);
		if (ans == 1) printf("0\n");
		else printf("1\n");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值