题意:问有多少条路径,符合路径上所有节点的权值乘积模1000003等于k。

解题关键:预处理阶乘逆元,然后通过hash和树形dp$O(1)$的判定乘积存在问题,注意此道题是如何处理路径保证不重复的,具有启发意义。

代码:2340ms,这段代码最重要的可取点就是如何通过操作省去memset的过程

复杂度:$O(n\log n)$

 #pragma comment(linker,"/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cmath>
#define maxn 100040
#define maxm 1000500
using namespace std;
typedef long long ll;
const ll mod=;
const ll inf=1ll<<;
ll n,k,ans,size,s[maxn],f[maxn],path[maxn],cr,val[maxn],inv[maxm],ansl,ansr;
ll head[maxn],cnt,root,pathid[maxn],flag[maxm],mp[maxm],ca;
bool vis[maxn];
struct edge{
ll to,nxt;
}e[maxn<<]; void add_edge(ll u,ll v){
e[cnt].to=v;
e[cnt].nxt=head[u];
head[u]=cnt++;
} inline ll read(){
char k=;char ls;ls=getchar();for(;ls<''||ls>'';k=ls,ls=getchar());
ll x=;for(;ls>=''&&ls<='';ls=getchar())x=(x<<)+(x<<)+ls-'';
if(k=='-')x=-x;return x;
} void get_root(ll u,ll fa){//get_root会用到size
s[u]=;f[u]=;//f是dp数组
for(ll i=head[u];i!=-;i=e[i].nxt){
ll v=e[i].to;
if(v==fa||vis[v]) continue;
get_root(v,u);
s[u]+=s[v];
f[u]=max(f[u],s[v]);
}
f[u]=max(f[u],size-s[u]);
root=f[root]>f[u]?u:root;
} void get_path_size(ll u,ll fa,ll dis){//同时获取size和depth,size是深度,depth是dis的意思
path[cr]=dis%mod*val[u]%mod;
pathid[cr]=u;
cr++;
s[u]=;
ll tm=path[cr-]%mod;
for(ll i=head[u];i!=-;i=e[i].nxt){
ll v=e[i].to;
if(v==fa||vis[v]) continue;
get_path_size(v,u,tm);
s[u]+=s[v];
}
} void getans(ll a,ll b){
if(a>b) swap(a,b);
if(ansl>a) ansl=a,ansr=b;
else if(ansl==a&&ansr>b) ansr=b;
} void work(ll u,ll fa){
vis[u]=true;
for(ll i=head[u];i!=-;i=e[i].nxt){
ll v=e[i].to;
if(v==fa||vis[v]) continue;
cr=;
get_path_size(v,u,);
for(ll j=;j<cr;j++){
if(path[j]*val[u]%mod==k) getans(pathid[j],u);
ll tm=k*inv[path[j]*val[u]%mod]%mod;
if(flag[tm]!=ca) continue;
getans(mp[tm],pathid[j]);
}
for(int j=;j<cr;j++){
ll tm=path[j];
if(flag[tm]!=ca||mp[tm]>pathid[j]) flag[tm]=ca,mp[tm]=pathid[j];
}
}
ca++;
for(ll i=head[u];i!=-;i=e[i].nxt){
ll v=e[i].to;
if(vis[v]||v==fa) continue;
size=s[v],root=;
get_root(v,u);
work(root,u);
}
// vis[u]=false;
} void init(){
memset(vis,,sizeof vis);
memset(head,-,sizeof head);
//memset(flag,0,sizeof flag);
ans=cnt=;
//ca=1;
} ll mod_pow(ll x,ll n,ll p){
ll res=;
while(n){
if(n&) res=res*x%p;
x=x*x%p;
n>>=;
}
return res;
} int main(){
ll a,b;
f[]=inf;inv[]=;
for(ll i=;i<;i++) inv[i]=mod_pow(i,mod-,mod);
ca=;
while(scanf("%lld%lld",&n,&k)!=EOF){
ca++;
init();
for(int i=;i<=n;i++) val[i]=read()%mod;
for(int i=;i<n-;i++){
a=read(),b=read();
add_edge(a,b);
add_edge(b,a);
}
size=n,root=;
get_root(,-);
ansl=ansr=inf;
work(root,-);
if(ansl==inf) printf("No solution\n");
else printf("%lld %lld\n",ansl,ansr);
}
return ;
}

最新文章

  1. [从产品角度学EXCEL 01]-EXCEL是怎样运作的
  2. MFC双缓存技术代码
  3. 开始写Effective系列总结一些前端的心得
  4. Json转换类库
  5. &lt;实训|第十二天&gt;用LVM对linux分区进行动态扩容
  6. ASP.NET中实现Session的负载均衡
  7. 误删除了mssql的表。 使用命令:drop table xxxx
  8. Bootstrap页面布局23 - BS折叠内容
  9. 根据终端分配不同的url地址
  10. Java同步块
  11. Android微信SDK API 调用教程1
  12. nyoj 1100 WAJUEJI which home strong!
  13. css详解笔记
  14. 物理卷操作命令:pvcreate,pvscan,pvdisplay.卷组操作命令:vgcreate,vgdisplay.
  15. OD: Exploit Me - Overwrite Nearby Varible
  16. 【开发技术】如何查看项目中struts的版本
  17. linux下双网卡的绑定
  18. C#生成JOSN字符串
  19. CPU HQ 什么意思
  20. 2016 Multi-University Training Contest 6 题解

热门文章

  1. PHP CURL 中文说明
  2. 【BZOJ4238】电压 DFS树
  3. EasyNVR RTSP转HLS(m3u8+ts)流媒体服务器前端构建之:bootstrap-datepicker日历插件的实时动态展现
  4. 九度OJ 1019:简单计算器 (基础题、DP)
  5. BZOJ4920: [Lydsy1706月赛]薄饼切割
  6. PHP Framework
  7. LeetCode:分发饼干【455】
  8. SpringBoot学习笔记(13):日志框架
  9. P3231 [HNOI2013]消毒
  10. ActiveMQ 了解