题目传送门
题意: 给你一个正整数 n n n,让你在区间 [ 1 , n − 1 ] [1,n-1] [1,n−1]中找出一个最长子序列 t i t_i ti,使得 ∏ i = 1 k t i m o d n = 1 \prod\limits_{i=1}^k t_i \mod n=1 i=1∏ktimodn=1。
思路: 首先,假定我们选择的序列包含数 a a a,设其他数的乘积为 x ( m o d n ) x(\mod n) x(modn),那么就有 a ∗ x ≡ 1 ( m o d n ) a * x ≡1(\mod n) a∗x≡1(modn),也就是 x x x是 a a a的逆元。那么 a a a就要满足 g c d ( a , n ) = 1 gcd(a,n)=1 gcd(a,n)=1,否则 a a a没有逆元,不可能入选。(至于证明,就是 e x g c d exgcd exgcd求逆元的过程,用到裴蜀定理。)
我们把所有与n互质的数在模
n
n
n意义下乘起来,可以得到一个小于
n
n
n的数
a
n
s
ans
ans,
a
n
s
ans
ans一定与
n
n
n互质(辗转相除的原理)。那么
a
n
s
ans
ans一定在前面出现过,如果
a
n
s
≠
1
ans≠1
ans=1,那么在答案序列中把那个数删掉就行了。
假设出了
a
n
s
ans
ans以外,其他数的乘积为
y
y
y,那么就有
a
n
s
∗
y
m
o
d
n
=
a
n
s
ans *y\mod n=ans
ans∗ymodn=ans,得到
y
m
o
d
n
=
1
y\mod n = 1
ymodn=1。
代码:
#define int long long
signed main()
{
int n;
cin>>n;
int tot = 1;
vector<int>ans;
for(int i=1;i<=n-1;i++)
{
if(__gcd(i,n)==1)
{
tot = tot * i % n;
ans.pb(i);
}
}
tot %= n;
if(tot!=1)
{
for(auto it = ans.begin();it!=ans.end();it++)
{
if(*it == tot)
{
ans.erase(it);
break;
}
}
}
cout<<ans.size()<<endl;
for(auto i:ans)
cout<<i<<" ";
return 0;
}