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×(prodk×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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值