题意:
给定一棵n个节点的树,并且根节点的编号为p,第i个节点有属性值vali, 定义F(i): 在以i为根的子树中,属性值是的合约数的节点个数。y 是 x 的合约数是指 y 是合数且 y 是 x 的约数。小埃想知道对1000000007取模后的结果.
思路:
有点类似之前做的一道CF题…就都是整体考虑。
一次DFS就可以了,从根开始,第一次碰到这个结点的时候F[i]减去当前这个的合约数出现的次数。回溯的时候,F[i]加上当前这个的合约数出现的次数,结果就是i的子树中是的合约数的节点个数(子树包括自己)。所以要预处理出每个数字的合约数。
这里提一下这个复杂度的估计…我以前对DFS的复杂度估计有误解…
我以前一直以为DFS的复杂度肯定是2^n这样的,现在考虑一下本身这个树也就n个结点,所以这里的复杂度是O(n*sqrt(val))。
下次看到子树有几个符合要求的结点时可以考虑这种思路。
代码:
typedef long long ll;
bool vis[10010];
vector<int>hys[10010];//每个数的合约数
vector<int>g[20010];
ll val[20010];
ll cnt[10010];//当前i出现的次数
ll F[20010];
void init()
{
memset(vis,0,sizeof(vis));
for(int i=2;i<=10000;i++)
{
if(!vis[i])
{
for(int j=2;i*j<=10000;j++)
vis[i*j]=true;
}
}
for(int i=2;i<=10000;i++)
{
if(vis[i])
{
for(int j=1;i*j<=10000;j++)
hys[i*j].push_back(i);
}
}
}
void dfs(int id,int par)
{
for(int i=0;i<hys[val[id]].size();i++)
F[id]-=cnt[hys[val[id]][i]];
cnt[val[id]]++;
for(int i=0;i<g[id].size();i++)
{
if(g[id][i]!=par)
dfs(g[id][i],id);
}
for(int i=0;i<hys[val[id]].size();i++)
F[id]+=cnt[hys[val[id]][i]];
}
int main()
{
int t,n,p,u,v;
init();
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&p);
for(int i=1;i<=n;i++)
g[i].clear();
for(int i=0;i<n-1;i++)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
for(int i=1;i<=n;i++)
scanf("%lld",&val[i]);
memset(F,0,sizeof(F));
memset(cnt,0,sizeof(cnt));
dfs(p,-1);
ll ans=0;
for(int i=1;i<=n;i++)
ans=(ans+i*F[i])%MOD;
/*for(int i=1;i<=n;i++)
printf("%lld ",F[i]);
printf("\n");*/
printf("%lld\n",ans);
}
return 0;
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!