C- Product 1 Modulo N (数论)
题目地址:https://codeforces.com/contest/1514/problem/C
题目大意:
给定一个数字n,以及一个1到n-1的序列,求序列的一个最长子序列B,使得B中的所有元素的积对n取模结果为1,输出该序列长度以及该序列。
题目简述:
数论题,可以通过打表寻找规律,本博客还是想力求证明一下该规律。
在查找了大量资料之后,我找到了一个帖子:
https://math.stackexchange.com/questions/441667/the-product-of-integers-relatively-prime-to-n-congruent-to-pm-1-pmod-n
如果无法打开链接,也可以看我后面的思路讲解。
思路:
这个帖子证明的内容是:
模n的最小非负简化剩余系的乘积对n取模的结果为正负1。
下面我们来着手证明这一点。
当n<=2的时候是毫无疑问的,我们直接假定n>2。
首先,我们假设一个模n的最小非负简化剩余系为A,对于A中的每一个数x,我们求x在模n意义下的小于n的逆元y,由逆元的性质我们可以对x和y的性质进行分类讨论。
1、当x!=y时
此时x和y有着两两对应的关系,x和y都与n互质。并且都属于A。
这是由于xy≡1(mod n)的意义就是x、y和n互质,倘若x或者y不属于A,那么根据简化剩余系的定义,此时gcd(xy,n)!=1,因此是不成立的。
2、当x==y时
此时有x2≡1(mod n),那么对于模n意义下的-x(即n-x)来说,其逆元也具有相同的性质即(n-x)2≡1(mod n)。
此时x和-x对n取模不同余。
我们可以假设x≡-x(mod n),根据同余的性质我们可以得知n|2x,但是此时n>2并且(x,n)=1,显然这是不成立的。
因此-x2≡-1(mod n)即x*(n-x)≡-1(mod n)
证明了以上之后,我们将目光放回A上来,。
当n大于2的时候,φ(n)必定为一个偶数,因此A中的个数满足两两配对原则。
所以A中的所有元素的乘积对n取模结果为正负一。
该结论的证。
题目思路:
我们将目光放回题目上。
假设最后求得的序列B的元素乘积为k,那么易知k≡1(mod n)因此B只有可能是模n的最小非负简化剩余系A的子集。
当最小剩余系的积模n为1的时候,答案就是A。
当最小剩余系的积模n为-1(即在模n意义下的n-1)的时候,答案应当去除n-1。
这就是本题的详细证明。
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<stack> #include<list> #include<queue> #define N 100086 #define ll long long using namespace std; const ll MOD= 1e9+7; ll n,ans=1; vector<ll>v; inline void read(ll &p) { p=0;char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') p=p*10+(ch-'0'),ch=getchar(); } inline int gcd(int a,int b) { if(b==0) return a; return gcd(b,a%b); } int main() { read(n); for(ll i=1;i<n;i++) if(gcd(i,n)==1) {v.push_back(i);ans=ans*i;ans%=n;} if(ans!=1) v.pop_back(); printf("%lld\n",v.size()); for(int i=0;i<v.size();i++) printf("%lld ",v[i]); return 0; }
拓展:
关于帖子最后一段话(remark):
对于奇数n,自身平方对n取模的个数为num=2l,l是对n进行质因数分解后不同的质因数个数。
一、当奇数n为质数的时候,num=2,此时我们可以证明威尔逊定理(当且仅当p为素数的时候,(p-1)!≡-1(mod p)),此时A中元素的乘积对n取模为-1。
二、当奇数n不为质数时,num可以被4整除,因此A中元素的乘积对n取模为1。
三、当n为偶数的时候,答案取决于质因数2的幂次。
这是由于对于x2≡1(mod 2k)的解的个数b
(1)k==1时b==1
(2)k==2时b==2
(3)k>2时b==4
y由此我们可以具体得出何时取得-1,何时取得1。