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$会有问题。

  1 //CF 716E
  2 //by Cydiater
  3 //2016.9.27
  4 #include <iostream>
  5 #include <cstring>
  6 #include <string>
  7 #include <algorithm>
  8 #include <queue>
  9 #include <map>
 10 #include <ctime>
 11 #include <cmath>
 12 #include <string>
 13 #include <cstdio>
 14 #include <cstdlib>
 15 #include <iomanip>
 16 using namespace std;
 17 #define ll long long
 18 #define up(i,j,n)        for(int i=j;i<=n;i++)
 19 #define down(i,j,n)        for(int i=j;i>=n;i--)
 20 const int MAXN=1e6+5;
 21 const int oo=0x3f3f3f3f;
 22 inline ll read(){
 23     char ch=getchar();ll x=0,f=1;
 24     while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
 25     while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
 26     return x*f;
 27 }
 28 map<ll,ll>cnt;
 29 ll N,mod,LINK[MAXN],len=0,pow10[MAXN],inv10[MAXN],root,sum,siz[MAXN],max_siz[MAXN],ans=0,dis[MAXN],deep[MAXN];
 30 struct edge{
 31     ll y,next,v;
 32 }e[MAXN];
 33 bool vis[MAXN];
 34 namespace solution{
 35     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;}
 36     inline ll quick_pow(ll a,ll b){
 37         ll tmp=1;
 38         while(b){
 39             if(b&1)tmp=(tmp*a)%mod;
 40             b>>=1;a=(a*a)%mod;
 41         }
 42         return tmp;
 43     }
 44     void make_root(int node,int fa){
 45         siz[node]=1;max_siz[node]=0;
 46         for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]&&e[i].y!=fa){
 47             make_root(e[i].y,node);
 48             siz[node]+=siz[e[i].y];
 49             max_siz[node]=max(max_siz[node],siz[e[i].y]);
 50         }
 51         max_siz[node]=max(max_siz[node],sum-max_siz[node]);
 52         if(max_siz[node]<max_siz[root])root=node;
 53     }
 54     void ex_gcd(ll a,ll b,ll &x,ll &y){
 55         if(b==0){x=1;y=0;return;}
 56         ex_gcd(b,a%b,x,y);
 57         ll t=x;x=y;y=t-a/b*y;
 58     }
 59     ll get_inv(ll num){
 60         ll x,y;
 61         ex_gcd(num,mod,x,y);
 62         return ((x%mod+mod)+mod)%mod;
 63     }
 64     void init(){
 65         N=read();mod=read();
 66         up(i,2,N){
 67             ll x=read()+1,y=read()+1,v=read();
 68             insert(x,y,v);
 69             insert(y,x,v);
 70         }
 71         if(mod<=1){
 72             cout<<N*(N-1)<<endl;
 73             exit(0);
 74         }
 75         pow10[0]=1;
 76         up(i,1,N)pow10[i]=(pow10[i-1]*10)%mod;
 77         up(i,0,N)inv10[i]=get_inv(pow10[i]);//pret
 78     }
 79     void dfs(ll node,ll fa){
 80         ll tmp=(((mod-dis[node])%mod+mod)*inv10[deep[node]]+mod)%mod;
 81         cnt[tmp]++;
 82         for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]&&e[i].y!=fa){
 83             dis[e[i].y]=((dis[node]*10)%mod+e[i].v)%mod;
 84             deep[e[i].y]=deep[node]+1;
 85             dfs(e[i].y,node);
 86         }
 87     }
 88     ll get_ans(int node,int fa){
 89         ll tmp=cnt[dis[node]%mod];
 90         for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]&&e[i].y!=fa){
 91             deep[e[i].y]=deep[node]+1;
 92             dis[e[i].y]=(dis[node]+(e[i].v*pow10[deep[node]])%mod)%mod;
 93             tmp+=get_ans(e[i].y,node);
 94         }
 95         return tmp;
 96     }
 97     ll col(int node,ll dist,int dep){
 98         dis[node]=dist%mod;deep[node]=dep;
 99         dfs(node,0);
100         cnt[0]--;
101         return get_ans(node,0);
102     }
103     void work(int node){
104         vis[node]=1;
105         cnt.clear();
106         ans+=col(node,0,0);
107         for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]){
108             cnt.clear();
109             ans-=col(e[i].y,e[i].v,1);
110             root=0;sum=siz[e[i].y];
111             make_root(e[i].y,0);
112             work(root);
113         }
114     }
115     void slove(){
116         root=0;max_siz[root]=oo;sum=N;
117         make_root(1,0);
118         work(root);
119     }
120     void output(){
121         cout<<ans<<endl;
122     }
123 }
124 int main(){
125     //freopen("input.in","r",stdin);
126     using namespace solution;
127     init();
128     slove();
129     output();
130 }
131     

时间: 2024-08-09 06:32:49

CF715C:Digit Tree的相关文章

【题解】Digit Tree

[题解]Digit Tree CodeForces - 716E 呵呵以为是数据结构题然后是淀粉质还行... 题目就是给你一颗有边权的树,问你有多少路径,把路径上的数字顺次写出来,是\(m\)的倍数. 很明显可以点分治嘛,我们可以按照图上的样子,把一条路径本来是\(12345678\)的路径,变成\(1234|5678\),我们记录图中左边的那种路径为\(f\)(往根),右边的那种路径为\(g\)(从根),记右边的那种到分治中心的深度为\(d\),那么这条路径就可以被表示成\(f\times 1

[Codeforces 715C] Digit Tree

[题目链接] https://codeforces.com/contest/715/problem/C [算法] 考虑点分治 一条路径(x , y)合法当且仅当 : d(x) * 10 ^ dep(x) + d(y) = 0(mod m) , 其中d(u)表示u到分治重心路径上数字拼接起来所形成的数 统计答案时 , 我们只需维护一个map , 维护10 ^ -dep(u) * d(u) (mod m) 然后计算每个点的贡献即可 时间复杂度 : O(NlogN ^ 2) [代码] #include

退役前的做题记录3

[CERC2017]Gambling Guide 设 \(f_u\) 表示 \(u\) 到 \(n\) 的期望. \(f_n=0\) \[f_u=1+\sum_{v\in suf_v}\frac{min(f_u,f_v)}{d_u}\] \[\rightarrow f_u=1+\sum_{v\in suf_u,f_v<f_u}\frac{f_v}{d_u}+\sum_{v\in suf_u,f_v\ge f_u}\frac{f_u}{d_u}\] \[\rightarrow f_u=\sum_{

331. Verify Preorder Serialization of a Binary Tree

/* * 331. Verify Preorder Serialization of a Binary Tree * 2016-7-9 by Mingyang * 这个题目我的绝对原创的思路是把number##变为#,这样不断地俄罗斯方块式的减少 * 到最后只剩下一个#,所以自己就这么做,然后用StringBuffer的replace功能 * 但是发现有一个case过不去,就是"9,#,92,#,#"为什么呢?就是因为我只把单个digit * 的数考虑进去,没有看92作为一个整体. *

easyui js取消选中 Tree 指定节点

取消所有选中 var rootNodes = treeObject.tree('getRoots'); for ( var i = 0; i < rootNodes.length; i++) { var node = treeObject.tree('find', rootNodes[i].id); treeObject.tree('uncheck', node.target); }

Maximum Depth of Binary Tree

这道题为简单题 题目: Given a binary tree, find its maximum depth.The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. 思路: 我是用递归做的,当然也可以用深搜和广搜,递归的话就是比较左右子树的深度然后返回 代码: 1 # Definition for a binary tre

538. Convert BST to Greater Tree 二叉搜索树转换为更大树

Given a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original BST is changed to the original key plus sum of all keys greater than the original key in BST. Example: Input: The root of a Binary Search Tree like thi

SPOJ375 Query on a tree

https://vjudge.net/problem/SPOJ-QTREE 题意: 一棵树,每条边有个权值 两种操作 一个修改每条边权值 一个询问两点之间这一条链的最大边权 点数<=10000 多组测试数据,case<=20 Example Input: 1 3 1 2 1 2 3 2 QUERY 1 2 CHANGE 1 3 QUERY 1 2 DONE Output: 1 3 #include<cstdio> #include<iostream> #include&

POJ 1741 Tree(树的点分治,入门题)

Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 21357   Accepted: 7006 Description Give a tree with n vertices,each edge has a length(positive integer less than 1001).Define dist(u,v)=The min distance between node u and v.Give an in