题解 保险箱

传送门
更加详细的讲解

上面题解里的式子不再写一遍了

  • 与「在不在mod n加法下的群中(能否通过加减得到这个数)」相关的问题可以尝试通过裴蜀定理转化为是否同余于gcd之类

于是考虑如何在可以接受的复杂度内判断一个 \(g\) 是否合法
\(k\) 个数都判断一遍肯定T了,发现我们只需要判断是否整除,于是可以预处理
首先一定有 \(g \mid gcd(m_k, n)\),所以可以将 \(m_i\) 都变成 \(gcd(m_i, m_k)\) 以去掉没有用的因子
然后考虑有且仅有所有 \(m_i\) 的因数不可以作为 \(g\)
所以可以记搜分解所有 \(m_i\),同时标记所有不合法的 \(g\)
然后枚举 \(g\) check即可

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 300010
#define ll long long
// #define int long long

char buf[1<<21], *p1=buf, *p2=buf;
inline ll read() {
	ll ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

ll n, k;
ll a[N];

namespace force{
	int uni[N], usiz, x;
	bool vis[100000010];
	inline void md(int& a, int b) {a+=b; a=a>=n?a-n:a;}
	void solve() {
		// cout<<double(sizeof(vis))/1000/1000<<endl;
		x=a[k];
		for (int i=1; i<=n; ++i) {
			vis[a[i]]=1;
			int tem=(a[i]+x)%n;
			while (tem!=a[i]) {
				vis[tem]=1;
				md(tem, x);
			}
		}
		int ans=0;
		for (int i=0; i<n; ++i) if (!vis[i]) ++ans;
		printf("%d\n", ans);
		exit(0);
	}
}

namespace task1{
	int uni[N], usiz, x;
	void solve() {
		x=a[k];
		for (int i=1; i<k; ++i) uni[++usiz]=a[i]%x;
		sort(uni+1, uni+usiz+1);
		usiz=unique(uni+1, uni+usiz+1)-uni-1;
		int ans=n;
		for (int i=1; i<=usiz; ++i) {
			ans-=(n-uni[i])/x;
		}
		cout<<ans<<endl;
	}
}

namespace task{
	unordered_map<ll, bool> mp;
	ll div[N], dcnt;
	void dfs(ll n) {
		if (mp.find(n)!=mp.end()) return ;
		mp[n]=1;
		for (int i=1; i<=dcnt; ++i) if (n%div[i]==0) dfs(n/div[i]);
	}
	void solve() {
		ll t=__gcd(a[k], n), t2=t;
		for (ll i=2; i*i<=t; ++i) {
			if (t2%i==0) {
				div[++dcnt]=i;
			 	do {t2/=i;} while (t2%i==0);
			}
		}
		if (t2>1) div[++dcnt]=t2;
		for (int i=1; i<k; ++i) dfs(__gcd(a[i], t));
		ll i=1;
		for (; i*i<=t; ++i) if (t%i==0 && mp.find(i)==mp.end()) {printf("%lld\n", n/i); exit(0);}
		for (--i; i; --i) if (t%i==0 && mp.find(t/i)==mp.end()) {printf("%lld\n", n/(t/i)); exit(0);}
	}
}

signed main()
{
	freopen("b.in", "r", stdin);
	freopen("b.out", "w", stdout);

	n=read(); k=read();
	for (int i=1; i<=k; ++i) a[i]=read();
	// force::solve();
	task::solve();

	return 0;
}
posted @ 2021-11-17 19:08  Administrator-09  阅读(0)  评论(0编辑  收藏  举报