[题解] Tenka1 Programmer Contest 2019 E

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;
}
原文地址:https://www.cnblogs.com/wxq1229/p/12556840.html