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\),有两种操作: '+'按钮 ...
随机推荐
- Bootstrap系列 -- 40. 导航条二级菜单
在导航条中添加二级菜单也非常简单 <div class="navbar navbar-default" role="navigation"> < ...
- WCF x509证书安装问题汇总
1.win7及以后系统可以使用certlm.msc打开localmachine的证书管理界面.win7前的版本需要使用mmc打开控制台,然后选择文件->添加删除管理单元->选择证书.2.部 ...
- 开发WP版本的大菠萝英雄榜
前言 想当年Team有无数人在玩大菠萝,我被忽悠进来做肉盾,选了蛮子,从1.0开始,经历了103.105.108.2.0.2.1.这个游戏对我最大的帮助是学习了不同的技术,比如XAML.比如xcode ...
- 网站flash黑屏问题
操作系统 专业回答 2012-04-12 20:44 看网站视频时,可以小屏看,不能最大化.最大化的时候,只有声音,图象卡住了不动. 解决办法: 1 打开视频 然后最大化 按键 击右健 设置 把加速硬 ...
- js滚动到底部事件
window.innerHeight表示窗口高度 $(document).height()返回文档高度 $(document).scrollTop()返回滚动条与顶部的距离,在最上部时为0,在最下部时 ...
- webpack入坑之旅(六)配合vue-router实现SPA
这是一系列文章,此系列所有的练习都存在了我的github仓库中vue-webpack,在本人有了新的理解与认识之后,会对文章有不定时的更正与更新.下面是目前完成的列表: webpack入坑之旅(一)不 ...
- [Google Guava]学习--新集合类型Multiset
Guava提供了一个新集合类型Multiset,它可以多次添加相等的元素,且和元素顺序无关.Multiset继承于JDK的Cllection接口,而不是Set接口. Multiset主要方法介绍: a ...
- 【日常笔记】datatables表格数据渲染
现在有很多表格渲染方式 这里只是记录怎么使用datatables渲染数据 使用datatables可以更方便的来渲染数据 [中文api]http://datatables.club/index.htm ...
- 系统间通信(8)——通信管理与RMI 上篇
1.概述 在概述了数据描述格式的基本知识.IO通信模型的基本知识后.我们终于可以进入这个系列博文的重点:系统间通信管理.在这个章节我将通过对RMI的详细介绍,引出一个重要的系统间通信的管理规范RPC, ...
- 【HDU 5833】Zhu and 772002(异或方程组高斯消元)
300个最大质因数小于2000的数,选若干个它们的乘积为完全平方数有多少种方案. 合法方案的每个数的质因数的个数的奇偶值异或起来为0. 比如12=2^2*3,对应的奇偶值为01(2的个数是偶数为0,3 ...