zoukankan      html  css  js  c++  java
  • UOJ#192. 【UR #14】最强跳蚤

    题目链接 http://uoj.ac/problem/192

    暑期课第二天

    树上问题进阶

    具体内容看笔记博客吧 

    题意

    n个节点的树T 边有边权w 求满足(u, v)上所有边权乘积为完全平方数的路径有多少条

    看到“所有边权乘积为完全平方数” 想到完全平方数的特殊性

    就是分解质因数后 质因数指数都为偶数

    然后就想到分解边权质因数+判质路径边权奇偶性

    后者由于奇数偶数的和的规律 可以使用抑或

    偶就表示为0 奇就表示为一

    那么如何存储呢?

    状压?

    空间之大 状压压不下

    所以hash 

    对每一个要用的质数 取一个 [1, 2 ^ 64] 的随机数

    出现一次就抑或一次即可

    然后。。。

    题意

    n个节点的树T 边有边权w 求满足(u, v)上所有边权抑或和为0的路径有多少条

    前缀和最常用的两种 一是累加和 二是抑或和

    明显可以使用前缀和

    又由于 a ^ a = 0

    对于一条路径 (路径两端点的lca) 到 (根节点)的那一段抑或两次没啦

    所以如果(u, v)上所有边权抑或和为0

    那么他们的抑或前缀和相等

    以下附莫名被ex扣下3分的辣鸡代码

     1 #include <cstdio>
     2 #include <algorithm>
     3 #include <cstdlib>
     4 #include <ctime>
     5 #include <map>
     6 using namespace std;
     7 const int N = 2e5 + 5;
     8 const int M = 1e4 + 5;
     9 
    10 int n, m;
    11 struct Edge{
    12     int u, v;
    13     long long w;
    14     int next;
    15 }edge[N << 1];
    16 int esize, head[N]; 
    17 long long p[M + 5], ps;
    18 bool np[M];
    19 long long num[N];
    20 map<int, long long> rf;
    21 
    22 inline void addedge(int x, int y, long long z){
    23     edge[++esize] = (Edge){x, y, z, head[x]};
    24     head[x] = esize;
    25 }
    26 
    27 inline void p_cal(){
    28     for(int i = 2; i < M; i++){
    29         if(!np[i]) p[++ps] = i;
    30         for(int j = 1; j <= ps && i * p[j] < M; j++){
    31             np[i * p[j]] = 1;
    32             if(!(i % p[j])) break;
    33         }
    34     }
    35 }
    36 
    37 inline void build(int x, int fa){
    38     for(int i = head[x]; i != -1; i = edge[i].next){
    39         int v = edge[i].v;
    40         if(v == fa) continue;
    41         num[v] = num[x] ^ edge[i].w;
    42         build(v, x);
    43     }
    44 }
    45 
    46 int main(){
    47     srand(time(NULL));
    48     scanf("%d", &n);
    49     p_cal();
    50     for(long long i = 1; i <= ps; i++)
    51         rf[p[i]] = ((long long)rand() << 30) + rand();
    52     //rd续命法 
    53     long long res;
    54     int x, y, z;
    55     for(int i = 0; i <= n; i++) head[i] = -1;
    56     for(int i = 1, x, y, z; i < n; i++){
    57         scanf("%d%d%d", &x, &y, &z);
    58         res = 0;
    59         int tmp = z;
    60         for(int j = 1; j <= ps && p[j] * p[j] <= tmp; j++)
    61             while(!(z % p[j])) 
    62                 res ^= rf[p[j]], z /= p[j];
    63         if(z != 1) {
    64             if(!rf[z])
    65                rf[z] = ((long long)rand() << 30) + rand();
    66                res ^= rf[z];
    67         }
    68         addedge(x, y, res); addedge(y, x, res);
    69     } 
    70 
    71     build(1, -1);
    72     sort(num + 1, num + n + 1);
    73     long long ans = 0;
    74     for(int i = 1, j; i <= n; i = j){
    75         j = i;
    76         while(num[j] == num[i] && j <= n) j++;
    77         ans += (long long)(j - i) * (j - i - 1);
    78     }
    79     printf("%lld", ans);
    80     return 0;    
    81 }
    View Code
  • 相关阅读:
    2018年9月28日CCPC秦皇岛站参赛总结
    数学:二次剩余与n次剩余
    数学:拓展Lucas定理
    BZOJ2301:莫比乌斯反演+二维容斥解决GCD范围计数
    数学:莫比乌斯反演-约数个数和
    数学:莫比乌斯反演-GCD计数
    关于cnblogs至github上blog的搬迁
    友链——一群dalao
    折半搜索(meet in the middle)
    关于爆搜
  • 原文地址:https://www.cnblogs.com/hjmmm/p/9398314.html
Copyright © 2011-2022 走看看