E. Kamil and Making a Stream 区间gcd

E. Kamil and Making a Stream

这个题目要用到一个结论,就是区间一个区间长度为n的不同的gcd不会超过logn 个,

其实就是知道这个题目可以暴力就好了。

然后就是对于每一个节点,我都存从祖先到这个节点的所有的gcd,用一个vector存下来。

然后因为这个vector的size 不会很大,所以就可以直接暴力往下转移。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <bitset>
#include <string>
#include <algorithm>
#include <iostream>
#include <map>
#define inf 0x3f3f3f3f
#define inf64 0x3f3f3f3f3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
typedef pair<ll, ll> P;
vector<P>val[maxn];
vector<int>G[maxn];
ll a[maxn], ans;

void add(int u, int v) {
    G[u].push_back(v);
    G[v].push_back(u);
}

ll gcd(ll a, ll b) {
    return b == 0 ? a : gcd(b, a%b);
}

void dfs(int u, int pre,int dep) {
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if (v == pre) continue;
        for (int j = 0; j < val[u].size(); j++) {
            P now = val[u][j];
            ll ans = gcd(now.first, a[v]);
            int len = val[v].size();
            if (len == 0 || ans != val[v][len - 1].first) val[v].push_back(make_pair(ans, now.second));
        }
        val[v].push_back(make_pair(a[v], dep + 1));
        dfs(v, u, dep + 1);
    }
}

void dfs1(int u, int pre) {
    for (int i = 1; i < val[u].size(); i++) {
        ans += (val[u][i].second - val[u][i - 1].second) % mod*val[u][i - 1].first%mod;
        ans %= mod;
    }
    ans += a[u] % mod;
    ans %= mod;
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if (v == pre) continue;
        dfs1(v, u);
    }
}
/*
void dfsprint(int u, int pre) {
    for (int i = 0; i < val[u].size(); i++) {
        printf("ww u=%d %lld %lld\n", u, val[u][i].first, val[u][i].second);
    }
    for (int i = 0; i < G[u].size(); i++) {
        int v = G[u][i];
        if (v == pre) continue;
        dfsprint(v, u);
    }
}
*/

int main() {
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
    for (int i = 1; i < n; i++) {
        int u, v;
        scanf("%d%d", &u, &v);
        add(u, v);
    }
    val[1].push_back(make_pair(a[1], 1));
    dfs(1, -1, 1);
    ans = 0;
    dfs1(1, -1);
//    dfsprint(1, -1);
    printf("%lld\n", ans);
    return 0;
}
 

原文地址:https://www.cnblogs.com/EchoZQN/p/11596062.html

时间: 2024-07-29 20:52:58

E. Kamil and Making a Stream 区间gcd的相关文章

Kamil and Making a Stream

E. Kamil and Making a Stream 参考:Codeforces Round #588 (Div. 2)-E. Kamil and Making a Stream-求树上同一直径上两两节点之间gcd的和 思路:求的就是1~n之间所有最短路的gcd之和. 用一个set来储存每一个结点可能的gcd,另外再用一个三维的map来记录每一个结点的每一个gcd出现的次数. 代码: // Created by CAD on 2019/9/28. #include <bits/stdc++.

dutacm.club 1094: 等差区间(RMQ区间最大、最小值,区间GCD)

1094: 等差区间 Time Limit:5000/3000 MS (Java/Others)   Memory Limit:163840/131072 KB (Java/Others)Total Submissions:655   Accepted:54 [Submit][Status][Discuss] Description 已知一个长度为 n 的数组 a[1],a[2],-,a[n],我们进行 q 次询问,每次询问区间 a[l],a[l+1],-,a[r?1],a[r] ,数字从小到大

HDU 5726 GCD 区间GCD=k的个数

GCD Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2742    Accepted Submission(s): 980 Problem Description Give you a sequence of N(N≤100,000) integers : a1,...,an(0<ai≤1000,000,000). There ar

区间 GCD

区间 GCD题目描述最近 JC 同学刚学会 gcd,于是迷上了与 gcd 有关的问题.今天他又出了一道这样的题目,想要考考你,你能顺利完成吗?给定一个长度为 n 的字符串 s[1..n],串仅包含小写字母.对于区间 [l, r],你需要回答 s[l..r]中有多少个长度为 3 的子序列组成了"gcd",即有多少组 (i, j, k) 满足 l ≤ i < j < k ≤ r, s[i] ='g', s[j] = 'c', s[k] = 'd'.输入格式第一行为一个字符串 s

bzoj 5028: 小Z的加油店——带修改的区间gcd

Description 小Z经营一家加油店.小Z加油的方式非常奇怪.他有一排瓶子,每个瓶子有一个容量vi.每次别人来加油,他会让 别人选连续一段的瓶子.他可以用这些瓶子装汽油,但他只有三种操作: 1.把一个瓶子完全加满: 2.把一个瓶子完全倒空: 3.把一个瓶子里的汽油倒进另一个瓶子,直到倒出瓶子空了或者倒进的瓶子满了. 当然,为了回馈用户,小Z会时不时选择连续一段瓶子,给每个瓶子容积都增加x. 为了尽可能给更多的人加油,每次客户来加油他都想知道他能够倒腾出的汽油量最少是多少? 当然他不会一点汽

Codeforces 914D - Bash and a Tough Math Puzzle 线段树,区间GCD

题意: 两个操作, 单点修改 询问一段区间是否能在至多一次修改后,使得区间$GCD$等于$X$ 题解: 正确思路; 线段树维护区间$GCD$,查询$GCD$的时候记录一共访问了多少个$GCD$不被X整除的区间即可,大于一个就NO 要注意的是,如果真的数完一整个区间,肯定会超时,因此用一个外部变量存储数量,一旦超过一个,就停止整个查询 #include <bits/stdc++.h> #define endl '\n' #define ll long long #define IO ios::s

FZU2224 An exciting GCD problem 区间gcd预处理+树状数组

分析:(别人写的) 对于所有(l, r)区间,固定右区间,所有(li, r)一共最多只会有log个不同的gcd值, 可以nlogn预处理出所有不同的gcd区间,这样区间是nlogn个,然后对于询问离线处理, 用类似询问区间不同数字的方法,记录每个不同gcd最后出现的位置,然后用树状数组进行维护 注:我是看了这段代码会的,但是他的nlogn预处理我不会,我会nlog^2n的 dp[i][j]代表以i为右端点,向左延伸2^j个点(包括i)的gcd,然后因为这样的gcd满足递减,所以可以二分找区间 代

hdu 5869 区间gcd的求法及应用

题意:长度n的序列, m个询问区间[L, R], 问区间内的所有连续子段的不同GCD值有多少种. 题解: 1.因为n个数的gcd等于前n-1个数的gcd值再于第n个数gcd一下的值,再加上如果固定终点,区间向前延伸越多gcd必定是非严格递减的,所以我们可以预处理出以每一个数为终点的所有的后缀的gcd,每次求出第i个数为终点后记录下所有的gcd值再与第i+1个数求gcd,这个很好做. 2.将所有的查询按右区间从小到大排序,同时将第一步记录的值在树状数组中更新,然后用树状数组区间求和就好了,这一步在

Luogu T9376 区间GCD

题目背景 无 题目描述 给定一长度为n的动态序列,请编写一种数据结构,要求支持m次操作,包括查询序列中一闭区间中所有数的GCD,与对一闭区间中所有数加上或减去一个值. 输入输出格式 输入格式: 第1行两个数n,m,表示序列长度和操作次数. 第2行n个数ai,表示给定序列. 第3行至第m+2行,每行3~4个数: (1) 1 x y k 表示将[x,y]上的所有数加上k. (2) 2 x y 表示询问[x,y]上所有数的GCD. 输出格式: 对所有操作2,输出一个数,表示询问结果. 输入输出样例 输