https://tenka1-2019.contest.atcoder.jp/tasks/tenka1_2019_e
首先所有系数(gcd)的质因子一定是满足条件的。
(p mid f(x))就相当于(f(x) equiv 0 pmod p)
然后显然(f(x) equiv f(xmod p) pmod p)
那么(f(x))膜(p)不管(x)取值如何都为(0)当且仅当(f(0),f(1),cdots f(p-1) equiv 0 pmod p)
即(f(x))在(mod p)下有因式(prod_{i=0}^{p-1} (x-i))。显然(prod_{i=0}^{p-1}(x-i) equiv 0 pmod p)
这样我们就可以考虑枚举(n)以内的质数(p),然后check,但上面那个式子并不方便,我们想找到一个更简单且与其等价的因式。
与其等价的因式应该是一个(p)次多项式
又因为(p)是素数,对与(p)互质的数(x)都有(x^{p-1} equiv 1 pmod p),那么(x^{p-1}-1 equiv 0 pmod p),所以(x^p-x equiv 0 pmod p)。我们就找到了一个((x,p)=1)时与上面那个柿子等价的东西。
如果((x,p) ot= 1),(p)是质数,那么显然有(p mid x),这种情况(x^p-x)还是满足要求的。
所以(p mid f(x))(不论(x)的取值),当且仅当(f(x))有因式(x^p-x)。
于是枚举(n)以内的质数(p),将系数对(p)取模,然后暴力做除法即可。
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
typedef double db;
typedef long long ll;
typedef pair<int,int> PII;
typedef vector<int> VI;
const int N=5e4+10;
int gcd(int x,int y) {return y?gcd(y,x%y):x;}
int vis[N],ps[N],tn;
void sieve(int n) {
rep(i,2,n+1) {
if (!vis[i]) ps[tn++]=i;
for (int j=0;j<tn&&i*ps[j]<=n;j++) {
vis[i*ps[j]]=1;
if (i%ps[j]==0) break;
}
}
}
int a[N],n;
bool check(int p) {
if (a[0]%p) return false;
static int f[N];
rep(i,0,n+1) f[i]=(a[i]%p+p)%p;
per(i,0,n-p+1) {
int j=i+p;
f[i+1]=(f[i+1]+f[j])%p;
f[j]=0;
}
rep(i,0,n+1) if (f[i]) return false;
return true;
}
set<int> ans;
int main() {
#ifdef LOCAL
freopen("a.in","r",stdin);
#endif
scanf("%d",&n),sieve(n);
int g=0;
per(i,0,n+1) scanf("%d",&a[i]),g=gcd(g,abs(a[i]));
for (int i=2;i*i<=g;i++) {
if (g%i==0) {
ans.insert(i);
while (g%i==0) g/=i;
}
}
if (g!=1) ans.insert(g);
rep(i,0,tn) if (check(ps[i])) ans.insert(ps[i]);
for (auto p:ans) printf("%d
",p);
return 0;
}