题意
有一个密码箱,0到n-1中的某些整数是它的密码。 且满足,如果a和b都是它的密码,那么(a+b)%n也是它的密码(a,b可以相等) 某人试了k次密码,前k-1次都失败了,最后一次成功了。 问:该密码箱最多有多少不同的密码。
题解
我们先把看做。
显然有这样一个性质:
是密码,一定是密码。
不是密码,及其因数一定不是密码。
如果能够算出最小的密码,那么最多密码数为(最小密码)
然后就可以做这道题了,先把最后一个密码与取。最小密码一定是这个数的因数。
然后把都和这个数取。那么现在的的因数都一定不是密码。
设约数个数为,时间复杂度
CODE
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 250005;
LL n, a[MAXN], q[MAXN], p[MAXN];
int m, k;
bool f[MAXN];
int main () {
scanf("%lld%lld", &n, &m);
for(int i = 1; i <= m; ++i) scanf("%lld", &a[i]);
a[m] = __gcd(a[m], n);
for(int i = 1; i < m; ++i) a[i] = __gcd(a[i], a[m]);
int cnt = 0;
for(int i = 1; 1ll*i*i <= a[m]; ++i) if(a[m]%i==0)
q[++cnt] = i, q[++cnt] = a[m]/i; //q存因数
for(int i = 2; 1ll*i*i <= a[m]; ++i) if(a[m]%i==0) {
p[++k] = i; //p存质因数
while(a[m]%i==0)a[m]/=i;
}
if(a[m]>1)p[++k] = a[m];
sort(q + 1, q + cnt + 1);
for(int i = 1; i < m; ++i) f[lower_bound(q + 1, q + cnt + 1, a[i]) - q] = 1;
for(int i = cnt; i >= 1; --i)
for(int j = 1; q[i]*p[j] <= q[cnt] && j <= k && !f[i]; ++j) { //log n
int k = lower_bound(q + 1, q + cnt + 1, q[i]*p[j]) - q; //log cnt
if(q[k] == q[i]*p[j] && f[k]) f[i] = 1;
}
int ans = 1; while(f[ans]) ++ans;
printf("%lld
", n/q[ans]);
}