CF715C:Digit Tree
一句话怎么说来着
算法+高级数据结构=OI
现在我感觉到的是
我会的算法+我会的高级数据结构=WA
这道题提交了三四十次,从刚看题到完全写好花了好几天..,主要死于看错费马小定理的适用条件。
下面是正经题解:
首先,这道题的难点不在于找到有多少个路径(很明显的点分治),而是判断一条路径是否合法。
按照点分治的一般套路。我们可以求出从一个点出发的所有路径,然而把所有路径组合起来就好了。
显然,对于把从$root$到所有子节点的路径的那个数只要不断的乘上去然后$modM$就行了。
所有我们面临的最主要的问题就是如何把两条路径组合起来。
首先,这里指的路径并不是两条完全相同的路径。比如说我们要验证从$node_i$经$root$到$node_j$的路径,我们应该求出$node_i \rightarrow root$数和$root \rightarrow node_j$的数。
不妨设这两个数的为别为$num_i$和$num_j$,把他们的长度(或者说是从根到$node$的深度)即为$deep_i$和$deep_j$,显然,如果$node_i \rightarrow node_j$的路径是合法的,我们可以得到以下关系。
$num_i+num_j \times 10^{deep_j} \equiv 0 (mod M)$
转换一下
$num_i \equiv -num_j \times 10^{-deep_j} (mod M)$
对于这个式子右边的,dfs一遍后用map存储即可。然后累加式子左边的即可。同时,要注意从统计式子右边完后,要-1,具体为什么实现的时候自己就能明白。
同时,$M$不一定为素数,所以这个模的意义一定要用乘法逆元或者欧拉函数什么的求,直接快速幂$M-2$会有问题。
//CF 716E //by Cydiater //2016.9.27 #include <iostream> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <ctime> #include <cmath> #include <string> #include <cstdio> #include <cstdlib> #include <iomanip> using namespace std; #define ll long long #define up(i,j,n) for(int i=j;i<=n;i++) #define down(i,j,n) for(int i=j;i>=n;i--) const int MAXN=1e6+5; const int oo=0x3f3f3f3f; inline ll read(){ char ch=getchar();ll x=0,f=1; while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } map<ll,ll>cnt; ll N,mod,LINK[MAXN],len=0,pow10[MAXN],inv10[MAXN],root,sum,siz[MAXN],max_siz[MAXN],ans=0,dis[MAXN],deep[MAXN]; struct edge{ ll y,next,v; }e[MAXN]; bool vis[MAXN]; namespace solution{ inline void insert(ll x,ll y,ll v){e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;e[len].v=v;} inline ll quick_pow(ll a,ll b){ ll tmp=1; while(b){ if(b&1)tmp=(tmp*a)%mod; b>>=1;a=(a*a)%mod; } return tmp; } void make_root(int node,int fa){ siz[node]=1;max_siz[node]=0; for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]&&e[i].y!=fa){ make_root(e[i].y,node); siz[node]+=siz[e[i].y]; max_siz[node]=max(max_siz[node],siz[e[i].y]); } max_siz[node]=max(max_siz[node],sum-max_siz[node]); if(max_siz[node]<max_siz[root])root=node; } void ex_gcd(ll a,ll b,ll &x,ll &y){ if(b==0){x=1;y=0;return;} ex_gcd(b,a%b,x,y); ll t=x;x=y;y=t-a/b*y; } ll get_inv(ll num){ ll x,y; ex_gcd(num,mod,x,y); return ((x%mod+mod)+mod)%mod; } void init(){ N=read();mod=read(); up(i,2,N){ ll x=read()+1,y=read()+1,v=read(); insert(x,y,v); insert(y,x,v); } if(mod<=1){ cout<<N*(N-1)<<endl; exit(0); } pow10[0]=1; up(i,1,N)pow10[i]=(pow10[i-1]*10)%mod; up(i,0,N)inv10[i]=get_inv(pow10[i]);//pret } void dfs(ll node,ll fa){ ll tmp=(((mod-dis[node])%mod+mod)*inv10[deep[node]]+mod)%mod; cnt[tmp]++; for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]&&e[i].y!=fa){ dis[e[i].y]=((dis[node]*10)%mod+e[i].v)%mod; deep[e[i].y]=deep[node]+1; dfs(e[i].y,node); } } ll get_ans(int node,int fa){ ll tmp=cnt[dis[node]%mod]; for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]&&e[i].y!=fa){ deep[e[i].y]=deep[node]+1; dis[e[i].y]=(dis[node]+(e[i].v*pow10[deep[node]])%mod)%mod; tmp+=get_ans(e[i].y,node); } return tmp; } ll col(int node,ll dist,int dep){ dis[node]=dist%mod;deep[node]=dep; dfs(node,0); cnt[0]--; return get_ans(node,0); } void work(int node){ vis[node]=1; cnt.clear(); ans+=col(node,0,0); for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]){ cnt.clear(); ans-=col(e[i].y,e[i].v,1); root=0;sum=siz[e[i].y]; make_root(e[i].y,0); work(root); } } void slove(){ root=0;max_siz[root]=oo;sum=N; make_root(1,0); work(root); } void output(){ cout<<ans<<endl; } } int main(){ //freopen("input.in","r",stdin); using namespace solution; init(); slove(); output(); }
CF715C:Digit Tree的更多相关文章
- 【Codeforces715C&716E】Digit Tree 数学 + 点分治
C. Digit Tree time limit per test:3 seconds memory limit per test:256 megabytes input:standard input ...
- Codeforces 716 E Digit Tree
E. Digit Tree time limit per test 3 seconds memory limit per test 256 megabytes input standard input ...
- 【题解】Digit Tree
[题解]Digit Tree CodeForces - 716E 呵呵以为是数据结构题然后是淀粉质还行... 题目就是给你一颗有边权的树,问你有多少路径,把路径上的数字顺次写出来,是\(m\)的倍数. ...
- 【Codeforces 715C】Digit Tree(点分治)
Description 程序员 ZS 有一棵树,它可以表示为 \(n\) 个顶点的无向连通图,顶点编号从 \(0\) 到 \(n-1\),它们之间有 \(n-1\) 条边.每条边上都有一个非零的数字. ...
- CF 716E. Digit Tree [点分治]
题意:一棵树,边上有一个个位数字,走一条路径会得到一个数字,求有多少路径得到的数字可以整除\(P\) 路径统计一般就是点分治了 \[ a*10^{deep} + b \ \equiv \pmod P\ ...
- [Codeforces 715C] Digit Tree
[题目链接] https://codeforces.com/contest/715/problem/C [算法] 考虑点分治 一条路径(x , y)合法当且仅当 : d(x) * 10 ^ dep(x ...
- CF716E Digit Tree 点分治
题意: 给出一个树,每条边上写了一个数字,给出一个P,求有多少条路径按顺序读出的数字可以被P整除.保证P与10互质. 分析: 统计满足限制的路径,我们首先就想到了点分治. 随后我们就需要考量,我们是否 ...
- codeforces716E (点分治)
Problem Digit Tree 题目大意 给一棵树,有边权1~9. 询问有多少个点对(i,j),将i--j路径上的数字依次连接后所形成新数字可以被k整除.gcd(K,10)=1 解题分析 点分治 ...
- Codeforces Round #372 (Div. 2)
Codeforces Round #372 (Div. 2) C. Plus and Square Root 题意 一个游戏中,有一个数字\(x\),当前游戏等级为\(k\),有两种操作: '+'按钮 ...
随机推荐
- 如何在Vue2中实现组件props双向绑定
Vue学习笔记-3 前言 Vue 2.x相比较Vue 1.x而言,升级变化除了实现了Virtual-Dom以外,给使用者最大不适就是移除的组件的props的双向绑定功能. 以往在Vue1.x中利用pr ...
- 文本域的宽度和高度应该用cols和rows来控制,还是 用width和height来控制
文本域宽度如果用cols来控制,缩放网页的时候文本域的宽度不会自动变化 用width来表示就会跟着网页缩放而缩放 看到下面一段文字: 对于内容至上的网页,在禁用CSS的情况下,HTML内容要做到易于阅 ...
- IE对象最后一个属性后不要加逗号,否则在IE7及以下版本中会报错
某函数返回一个对象,如果在最后一个属性后加逗号,IE7及以下版本中会报错 正确代码: return{ top:rect.top-top, bottom:rect.bottom-top, left:re ...
- PHP 文件创建/写入
<?php /* PHP 文件创建/写入 fopen() 函数也用于创建文件.也许有点混乱, 但是在 PHP 中,创建文件所用的函数与打开文件的相同. 如果您用 fopen() 打开并不存在的文 ...
- eclipse下package的命名规范
Java的包名都有小写单词组成,类名首字母大写:包的路径符合所开发的 系统模块的 定义,比如生产对生产,物资对物资,基础类对基础类.以便看了包名就明白是哪个模块,从而直接到对应包里找相应的实现. 由于 ...
- MySQL server PID file could not be found!
重启mysql提示MySQL server PID file could not be found! Starting MySQL...The server quit without updating ...
- tomcat 的安全规范
下面来说一下,日常工作当中我们需要注意的一些tomcat的安全规范: 一:telnet管理端口的保护 类别 配置内容及其说明 标准配置 备注 Telnet 管理端口的保护 (强制) (1)配置文件中的 ...
- 如何改变tableview的section的颜色
方法一:调用 - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{ UIV ...
- Laplacian算子
多元函数的二阶导数又称为Laplacian算子: \[ \triangledown f(x, y) = \frac {\partial^2 f}{\partial x^2} + \frac {\par ...
- poj1655 树的重心 树形dp
树的重心定义为:找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,生成的多棵树尽可能平衡. 处理处每个节点的孩子有几个,和树的大小就好了. #include< ...