[启发式合并 乱搞] 计蒜客 10447 立方数路径

来源:互联网 发布:黄金是怎么形成的 知乎 编辑:程序博客网 时间:2024/06/16 20:56

可以在LCA处统计答案 然后考虑向上启发式合并
怎么统计答案 注意到 质因子的个数只有30个 我们用330个数字来表示状态 然后就是每位在模3意义下的加减法 不过并没有想到什么好的方法 比如转化为位运算来实现 所以在rxd的指导下 对36打表 然后分五段查表 复杂度减小了些

#include<cstdio>#include<cstdlib>#include<algorithm>#include<vector>#include<cstring>#include<tr1/unordered_map>#define cl(x) memset(x,0,sizeof(x))#define pb push_backusing namespace std;using namespace std::tr1;  typedef long long ll;inline char nc(){  static char buf[100000],*p1=buf,*p2=buf;  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}inline int read(int &x){  char c=nc(),b=1;  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1; else if (c==EOF) return 0;  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b; return 1;}inline void read(ll &x){  char c=nc(),b=1;  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;}const int K=729;int sum[K][K],inv[K];inline void div(int x,int *a){  for (int i=0;i<6;i++) a[i]=x%3,x/=3;}inline int com(int *a){  int ret=0; for (int i=5;~i;i--) ret=ret*3+a[i]; return ret;}inline void Pre(){  int a[6],b[6];  for (int i=0;i<K;i++){    div(i,a);    for (int j=0;j<6;j++) a[j]=(3-a[j])%3;    inv[i]=com(a);  }  for (int i=0;i<K;i++)    for (int j=0;j<K;j++){      div(i,a); div(j,b);      for (int k=0;k<6;k++) (a[k]+=b[k])%=3;      sum[i][j]=com(a);    }}inline ll Sum(ll x,ll y){  ll ret=0; int a[5],b[5];  for (int i=0;i<5;i++) a[i]=x%K,x/=K,b[i]=y%K,y/=K;  for (int i=0;i<5;i++) a[i]=sum[a[i]][b[i]];  for (int i=4;~i;i--) ret=ret*K+a[i];  return ret;}inline ll Inv(ll x){  ll ret=0; int a[5];  for (int i=0;i<5;i++) a[i]=x%K,x/=K;  for (int i=0;i<5;i++) a[i]=inv[a[i]];  for (int i=4;~i;i--) ret=ret*K+a[i];  return ret;}const int N=50005;struct edge{  int u,v,next;}G[N<<1];int head[N],inum;inline void add(int u,int v,int p){  G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;}int n,m; ll Ans;ll val[N],prime[35];inline ll calc(ll x){  ll ret=0;  for (int i=1;i<=30;i++){    int cnt=0;    if (prime[i]) while (x%prime[i]==0) cnt++,x/=prime[i];    ret=ret*3+cnt%3;  }  return ret;}typedef unordered_map<ll,int> Set;typedef unordered_map<ll,int>::iterator ITER;Set _S[N],*S[N];inline int Count(Set *s,ll x){  if (s->count(x)) return (*s)[x];  return 0;}inline Set *Merge(Set *s1,Set *s2,ll tmp){  if (s1->size()<s2->size()) swap(s1,s2);  for (ITER i=s2->begin();i!=s2->end();i++)    Ans+=(ll)i->second*Count(s1,Sum(tmp,Inv(i->first)));  for (ITER i=s2->begin();i!=s2->end();i++)    (*s1)[i->first]+=i->second;  return s1;}#define V G[p].vinline void dfs(int u,int fa){  val[u]=Sum(val[u],val[fa]);  _S[u].clear(); _S[u][val[u]]++; S[u]=&_S[u];  ll tmp=Sum(val[u],val[fa]);  for (int p=head[u];p;p=G[p].next)    if (V!=fa){      dfs(V,u);      S[u]=Merge(S[u],S[V],tmp);    }}int main(){  int iu,iv;  freopen("t.in","r",stdin);  freopen("t.out","w",stdout);  Pre();  while (read(n)){    read(m); for (int i=1;i<=m;i++) read(prime[i]);    for (int i=1;i<=n;i++) read(val[i]),val[i]=calc(val[i]),Ans+=val[i]==0;    for (int i=1;i<n;i++) read(iu),read(iv),add(iu,iv,++inum),add(iv,iu,++inum);    dfs(1,0);    printf("%lld\n",Ans);    Ans=0; cl(head); inum=0;  }  return 0;}
0 0
原创粉丝点击