CF1514C Product 1 Modulo N
目录
知识点: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;
}