传送门

一句话怎么说来着

算法+高级数据结构=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的更多相关文章

  1. 【Codeforces715C&716E】Digit Tree 数学 + 点分治

    C. Digit Tree time limit per test:3 seconds memory limit per test:256 megabytes input:standard input ...

  2. Codeforces 716 E Digit Tree

    E. Digit Tree time limit per test 3 seconds memory limit per test 256 megabytes input standard input ...

  3. 【题解】Digit Tree

    [题解]Digit Tree CodeForces - 716E 呵呵以为是数据结构题然后是淀粉质还行... 题目就是给你一颗有边权的树,问你有多少路径,把路径上的数字顺次写出来,是\(m\)的倍数. ...

  4. 【Codeforces 715C】Digit Tree(点分治)

    Description 程序员 ZS 有一棵树,它可以表示为 \(n\) 个顶点的无向连通图,顶点编号从 \(0\) 到 \(n-1\),它们之间有 \(n-1\) 条边.每条边上都有一个非零的数字. ...

  5. CF 716E. Digit Tree [点分治]

    题意:一棵树,边上有一个个位数字,走一条路径会得到一个数字,求有多少路径得到的数字可以整除\(P\) 路径统计一般就是点分治了 \[ a*10^{deep} + b \ \equiv \pmod P\ ...

  6. [Codeforces 715C] Digit Tree

    [题目链接] https://codeforces.com/contest/715/problem/C [算法] 考虑点分治 一条路径(x , y)合法当且仅当 : d(x) * 10 ^ dep(x ...

  7. CF716E Digit Tree 点分治

    题意: 给出一个树,每条边上写了一个数字,给出一个P,求有多少条路径按顺序读出的数字可以被P整除.保证P与10互质. 分析: 统计满足限制的路径,我们首先就想到了点分治. 随后我们就需要考量,我们是否 ...

  8. codeforces716E (点分治)

    Problem Digit Tree 题目大意 给一棵树,有边权1~9. 询问有多少个点对(i,j),将i--j路径上的数字依次连接后所形成新数字可以被k整除.gcd(K,10)=1 解题分析 点分治 ...

  9. Codeforces Round #372 (Div. 2)

    Codeforces Round #372 (Div. 2) C. Plus and Square Root 题意 一个游戏中,有一个数字\(x\),当前游戏等级为\(k\),有两种操作: '+'按钮 ...

随机推荐

  1. Scala入门详解

    object作为Scala中的一个关键字,相当于Java中的public static class这样的一个修饰符,也就说object中的成员都是静态的! 所以我们在这个例子中的main方法是静态的, ...

  2. 移除首页->重回首页

    之前发布了一篇文章<订餐系统之获取淘宝外卖订单>,因为是关于淘宝外卖的,所以文中出现这个词时,都加了链接,还设置了 target='_blank',就是为了让看的人方便点击,查看.后来,博 ...

  3. 20160307 - 双击打开 Js 扩展名的附件要保持留心

    Windows Script Host 技术是一门很老的技术,它让 Windows 的自带脚本 VBScript 和 JScript 可以操作 Windows ActiveX 对象,这样的脚本具有本地 ...

  4. BI的相关问题[转]

    什么是BI? Business Intelligence(BI) = Data Warehouse(DW) + OLAP + Data Mining(DM) 商业智能=数据仓库+联机分析+数据挖掘 做 ...

  5. [BZOJ1016][JSOI2008]最小生成树计数(结论题)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1016 分析: 首先有个性质:如果边集E.E'都可以表示一个图G的最小生成树(当然E和E ...

  6. Oracle在中文环境下出现乱码解决办法

       zysong.ttf下载是一款oracle字体乱码解决工具,实质于缺乏中文字体包! 01情况的例子 02情况的例子 01.在开始安装的时候出现乱码 下载zysong.ttf,unzip 解压 一 ...

  7. Socket,TCP/IP,UDP,HTTP,FTP

    1.Socket:套接字,是传输层协议的一种编程API 作用:用于描述IP地址和端口,区分来自不同应用程序的通信,实现数据传输的并发服务 JDK  Socket:在java.net包下有两个类Sock ...

  8. 【51NOD 1478】括号序列的最长合法子段

    很恶心啊,一道水题改了半天,主要是各种细节没有注意到,包括左括号剩余时有可能会出错的情况,需要从后往前扫 贡献一组测试数据: ((()))())(())(( 答案:8 1 #include<cs ...

  9. jQ1.5中的事件系统(低版本的事件系统)

    jQ的一个个版本事系统都在修正着bug和不断优化, 而且看了事件系统对事件的兼容更加熟悉, 更加了解jQ内部的事件机制. 因为jQ对事件系统引入了事件命名空间,事件的代理, 事件的手动触发,事件描述等 ...

  10. DEDE列表页直接获取下载链接

    我们得去设置软件频道的东西,先点击“核心”->"内容管理模型"中的软件模型进行编辑,将softlinks加入列表字段. 然后进入“系统”->"软件频道设置&q ...