タイトル
トピックリンク:https://jzoj.net/senior/#main/show/3799
思考
番号は完璧な正方形である場合、それは品質係数の分解である場合にだけ、素因数の各素数のためにもです。
ための\(N- \のLeq 90 \) 、これの最大\(24 \)素数。圧力のように考えてみましょう。
したがって、我々は前処理\(PRMSを[X] \)数を表す\(X \)品質係数、奇数のインデックスセットの品質因子の分解後。
セット\(F [X] [S ] \) に処理を表す(DAG \)\点\(X \) 、終点\(X \)すべてのパスでは、どのように多くの指標プライム奇数セットです\(S \)パス。
ですので\(DAG \)ので、二回サイドダウンパスを心配しないでください。
次いでため\(DAG \)の各側\((Y、X)\) 、我々は
[\ FをX] [S \ XOR \ PRMS [X] = \和^ {(Y、X) } _ {Y} F [Y
] [S] \] 答え\(\ ^ {N-SUM _ {I} 1} = F [I] [0] \)。
アルゴリズムの時間と空間の複雑さをしている\(O(N2メートル^)\) 、スペースを揚げされます。
実際に、より大きい全ての粒子は、我々を発見した(FRAC {90} {\ \ 2} \) ので素数は、役に立たない\(\ 1 \ SIM N)のみ素数自体の素因数の数を含んで、このパスは点が含まれている場合、したがって、この経路は、素因数1の素数が存在しなければなりません。
それは、より大きくなる(FRAC {90} {\ \ \ 2}) この点はどんな貢献発生しないので、我々は単に、あなたが直接、この点を削除することができ、図には表示されませんすることができ素数。
あまり有用素因数のみ\(2,3,5,7,11,13,17,19,23,29,31,37,41,43 \)この\(14 \)の一つ。
そのような時間的な複雑さはにドロップされ(O(N 2 ^ {14})\)\、この問題は失っていたことができます。
コード
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=100,M=8010,MAXN=(1<<14);
const int prime[15]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43};
int n,m,tot,head[N],prmS[N],in[N];
ll ans,f[N][MAXN];
struct edge
{
int next,to;
}e[M];
void add(int from,int to)
{
e[++tot].to=to;
e[tot].next=head[from];
head[from]=tot;
}
void topsort()
{
queue<int> q;
for (int i=1;i<=n;i++)
if (!in[i]) q.push(i);
for (int i=1;i<=n;i++)
f[i][prmS[i]]=1;
while (q.size())
{
int u=q.front();
q.pop();
for (int i=head[u];~i;i=e[i].next)
{
int v=e[i].to;
for (int j=0;j<MAXN;j++)
f[v][j^prmS[v]]+=f[u][j];
in[v]--;
if (!in[v]) q.push(v);
}
}
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d",&n,&m);
for (int i=1,x,y;i<=m;i++)
{
scanf("%d%d",&x,&y);
if (x==47||x==53||x==59||x==61||x==67||x==71||x==73||x==79||x==83||x==89) continue;
if (y==47||y==53||y==59||y==61||y==67||y==71||y==73||y==79||y==83||y==89) continue;
add(x,y); in[y]++;
}
for (int i=2;i<=n;i++)
for (int p=i,j=1;prime[j]<=p && j<=14;j++)
if (!(p%prime[j]))
{
bool cnt=0;
for (;!(p%prime[j]);p/=prime[j]) cnt^=1;
if (cnt) prmS[i]|=(1<<j-1);
}
topsort();
for (int i=1;i<=n;i++)
if (i!=47&&i!=53&&i!=59&&i!=61&&i!=67&&i!=71&&i!=73&&i!=79&&i!=83&&i!=89)
ans+=f[i][0];
printf("%lld",ans);
return 0;
}