題意
給你一個大數由n個可重複的質數相乘,要求求出一個這個大數的約數的子集,使得這個子集裏面的數兩兩互補爲對方的倍數
分析
考慮這樣的子集是什麼樣子的
把一個數向所有的約數連一條有向邊,然後就是等於求最長反鏈(即選出最多的點兩兩不到達)
又由於最長反鏈 = 最小鏈覆蓋(即選出最少的鏈覆蓋所有的點,每個點至少覆蓋一次)
發現這樣的圖是以質數的冪次來分層的,而且只有不同層之間連邊,我們只需要找到點數最大的層
現在問題就變成了每個質數都有個,選出 個,使得的方案數
這可以用生成函數來解決,並且因爲係數都是1,乘完之後的生成函數是中間凸兩邊低的(並且是對稱的)
兩個這樣的生成函數乘起來還是符合這個性質,所以最中間的係數是最大的,即時最大
代碼
#include <bits/stdc++.h>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace __gnu_pbds;
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> splay;
const int N = 200010;
const int mod = 998244353;
inline int read()
{
int p=0; int f=1; char ch=getchar();
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
int qpow(int x,int k,int mo)
{
int s = 1;
while(k)
{
if(k&1) s=(ll) s*x%mo;
x=(ll) x*x%mo; k>>=1;
}return s;
}
int r[N<<2];
void dft(int *a,int n,int op)
{
for(int i=0;i<n;i++) if(r[i] > i) swap(a[r[i]] , a[i]);
for(int i=1;i<n;i<<=1)
{
int gn = qpow(3ll,(mod-1) / (i<<1), mod);
for(int j=0;j<n;j+=(i<<1))
{
int g = 1;
for(int k=0;k<i;k++,g=(ll) g*gn%mod)
{
int x = a[j+k]; int y = (ll) a[j+k+i] * g % mod;
a[j+k] = (x+y)%mod;
a[j+k+i] = (x-y+mod)%mod;
}
}
}
if(op==-1) reverse(a+1,a+n);
}
int A[N<<2],B[N<<2],C[N<<2];
struct node
{
vector<int> a;
node(){}
friend node operator * (node x,node y)
{
int m = x.a.size() + y.a.size() - 2; int n,l=0;
for(n=1;n<=m;n<<=1) l++;
for(int i=0;i<n;i++) A[i] = B[i] = C[i] = 0;
for(int i=0;i<x.a.size();i++) A[i] = x.a[i];
for(int i=0;i<y.a.size();i++) B[i] = y.a[i];
r[0] = 0; for(int i=1;i<n;i++) r[i] = (r[i>>1] >> 1) | ((i&1) << (l-1));
dft(A,n,1); dft(B,n,1);
for(int i=0;i<n;i++) C[i] = (ll) A[i] * B[i] % mod;
dft(C,n,-1); int invn = qpow(n,mod-2,mod);
for(int i=0;i<n;i++) C[i] = (ll) C[i] * invn % mod;
node z; for(int i=0;i<=m;i++) z.a.pb(C[i]); return z;
}
}p[400010]; int tot = 0;
int cnt[3000010];
priority_queue<pii>q;
int d[N];
int main()
{
// freopen("a.in","r",stdin);
int n = read(); while(!q.empty()) q.pop();
for(int i=1;i<=n;i++) d[i] = read(),cnt[d[i]]++;
for(int i=1;i<=3000000;i++) {
if(cnt[i]) {
tot ++;
for(int j=0;j<=cnt[i];j++) p[tot].a.pb(1);
q.push(mp(-cnt[i]-1,tot));
}
}
while(q.size() > 1) {
pii x = q.top(); q.pop();
pii y = q.top(); q.pop();
p[x.se] = p[x.se] * p[y.se]; p[y.se].a.clear();
q.push(mp(-p[x.se].a.size(),x.se));
}
return printf("%d\n",p[q.top().se].a[(n+1)/2]),0;
}