知识点:GCD、同余
题意
输出1~n-1组成的序列中最长子序列使得元素乘积模n为1
思路
出现模、n与比n小的数关联、因子等特征,可考虑gcd。
假设最长子序列为a,即
(
∏
a
i
)
%
n
=
1
(\prod a_i)\% n=1
(∏ai)%n=1,若再加入一个数c得
(
∏
a
i
)
×
c
%
n
=
(
∏
a
i
)
%
n
×
c
%
n
=
c
(\prod a_i)\times c\% n=(\prod a_i)\% n \times c\% n=c
(∏ai)×c%n=(∏ai)%n×c%n=c,可知模不为1的子序列去掉该模后可以得到模为1的子序列。
对原序列而言,如果原序列乘积模n大于1,则去掉序列中该模即为最长子序列。
我第一次尝试考虑存在模n为0的情况。说明乘积包含因子n,但因子n可以分解为最小因子,分布到不同元素中(比如n=6时,2和3分布到2、3和4中),情况很多。
实际上模为1是特殊的情况,说明乘积和n互质,即乘积和n没有共同因子。如果存在共同因子,即
(
g
c
d
×
p
r
o
d
)
%
(
g
c
d
×
c
)
(gcd\times prod) \% (gcd\times c)
(gcd×prod)%(gcd×c)可转换为求
(
g
c
d
×
p
r
o
d
)
−
k
×
(
g
c
d
×
c
)
(gcd\times prod) - k\times(gcd\times c)
(gcd×prod)−k×(gcd×c)的最小非负解,移项发现
g
c
d
×
(
p
r
o
d
−
k
×
c
)
gcd \times (prod-k\times c)
gcd×(prod−k×c),无论k取何值,模只能为gcd的倍数,而gcd>1,所以不可能为1。更有根据gcd的定义,
g
c
d
(
p
r
o
d
,
n
)
≠
1
gcd(prod,n)\neq 1
gcd(prod,n)=1就是
g
c
d
(
p
r
o
d
%
n
,
n
)
≠
1
gcd(prod\%n,n)\neq 1
gcd(prod%n,n)=1,gcd不为1那么
p
r
o
d
%
n
prod\%n
prod%n更不可能为1。
易得
g
c
d
(
p
r
o
d
,
n
)
=
1
gcd(prod,n)=1
gcd(prod,n)=1则
g
c
d
(
a
i
,
n
)
=
1
(
p
r
o
d
=
∏
a
i
)
gcd(a_i,n)=1\quad (prod=\prod a_i)
gcd(ai,n)=1(prod=∏ai),那么除去所有与n不互质的元素再除去模对应的元素即为所求序列。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll n;
void solve()
{
scanf("%lld",&n);
ll fact=1;
set<ll> st;
for(ll i=1;i<n;i++)
{
if(__gcd(n,i)!=1) continue;//直接跳过与n不互质的元素相当于除去
fact=fact*i%n;//同时计算除去不互质数后的模
st.insert(i);//也可以用线性结构
}
if(st.count(fact)) st.erase(fact);//除去模对应的元素
st.insert(1);//和1的gcd一定是1,上面就被跳过了,或者上面模
//已经为1,把1除去了。这里再加回来
printf("%lld\n",st.size());
for(auto v:st)
printf("%lld ",v);
puts("");
}
int main()
{
// ll t;
// scanf("%lld",&t);
// while(t--)
solve();
return 0;
}