牛客练习赛77 部分题解

比赛链接

A  小G的sum

的最小的约数是

的最大的约数是

#include<bits/stdc  .h>using namespace std ;int main(){    std::ios::sync_with_stdio(false) , cin.tie(0) ;    int n ;    cin >> n ;    long long ans1 = n ;    long long ans2 = 1ll * n * (n   1) / 2 ;    cout << ans1   ans2 << '\n' ;    return 0 ;}

B  小G的GCD

#include<bits/stdc  .h>using namespace std ;int main(){    std::ios::sync_with_stdio(false) , cin.tie(0) ;    int n , k ;    long long ans = 0 ;    cin >> n >> k ;    auto cal = [&](int x)    {        return 1ll * k * x * (x   1) / 2 ;    } ;    for(int i = 1 ; i <= n ; i   )  ans  = cal(i / k) ;    cout << ans << '\n' ;    return 0 ;}

C  小G的约数

,整除分块即可。

#include<bits/stdc  .h>using namespace std ;int main(){    std::ios::sync_with_stdio(false) , cin.tie(0) ;    int n ;    cin >> n ;    auto cal = [&](long long l , long long r)    {        long long a1 = l ;        long long n = r - l   1 ;        long long d = 1 ;        return n * a1   n * (n - 1) * d / 2 ;    } ;    auto G = [&](long long n)    {        long long ans = 0 ;        for(long long l = 1 , r ; l <= n ; l = r   1)        {         r = n / (n / l) ;         ans  = 1ll * cal(l , r) * (n / l) ;        }        return ans ;    } ;    cout << G(G(n)) << '\n' ;    return 0 ;}

D  小G的LY数对

开局有人

分钟过了,以为直接暴力

做就行,

成瓜皮。

仔细分析

等价于

具体写的时候要容斥,因为会算重复。

时间复杂度降低为

#include<bits/stdc  .h>using namespace std ;int main(){    std::ios::sync_with_stdio(false) , cin.tie(0) ;    int n , m ;    cin >> n >> m ;    vector<int> a(n) ;    vector<int> b(m) ;    for(int i = 0 ; i < n ; i   )  cin >> a[i] ;    for(int i = 0 ; i < m ; i   )  cin >> b[i] ;    vector<int> c , d ;    for(int i = 0 ; i < n ; i   )        for(int j = 0 ; j < 30 ; j   )            c.push_back((a[i] ^ (1 << j))) ;    for(int i = 0 ; i < m ; i   )        for(int j = 0 ; j < 30 ; j   )            d.push_back((b[i] ^ (1 << j))) ;    long long ans = 0 ;    sort(c.begin() , c.end()) ;    sort(d.begin() , d.end()) ;    int cur = 0 ;    int siz1 = c.size() , siz2 = d.size() ;    for(int i = 0 ; i < siz1 ; i   )    {        int j = i ;        while(j   1 < siz1 && c[j   1] == c[j])  j    ;        while(cur   1 < siz2 && d[cur] < c[i])  cur    ;        int p = cur ;        if(c[i] == d[cur])        {            while(p   1 < siz2 && d[p   1] == d[p])  p    ;            ans  = 1ll * (j - i   1) * (p - cur   1) ;            //cout << c[i] << ' ' << j - i   1 << ' ' << p - cur   1 << '\n' ;            cur = p ;        }            i = j ;    }    //cout << ans << '\n' ;    sort(a.begin() , a.end()) ;    sort(b.begin() , b.end()) ;    cur = 0 ;    siz1 = a.size() , siz2 = b.size() ;    for(int i = 0 ; i < siz1 ; i   )    {        int j = i ;        while(j   1 < siz1 && a[j   1] == a[j])  j    ;        while(cur   1 < siz2 && b[cur] < a[i])  cur    ;        int p = cur ;        if(a[i] == b[cur])        {            while(p   1 < siz2 && b[p   1] == b[p])  p    ;            ans -= 1ll * (j - i   1) * (p - cur   1) * 30 ;            cur = p ;        }            i = j ;    }    cout << ans / 2 << '\n' ;    return 0 ;}

E  小G的GLS图

首先分析是否存在某种数学关系,从而避免建图找割点。但是手画一些

,会发现不建图无法找到割点。

然后就开始思考如何简化建边,不能直接暴力建边

。然后思考质因子分解,每个质因子在

个数存在,直接建边是

的,但是发现我其实只要建出一个长度是

的环就好了,没必要建出稠密图。

因此建出图跑一遍

求割点就好了。

时间复杂度的瓶颈是质因子分解。

#include<bits/stdc  .h>using namespace std ;const int maxn = 1e7   10 ;int cnt = 0 ;bool vis[maxn] ;int prime[maxn] ;int id[maxn] ;void get_prime(int up) //素数筛{    memset(vis , 0 , sizeof(vis)) ;    vis[1] = 1 ;    for(int i = 2 ; i <= up ; i   )    {        if(!vis[i])         prime[   cnt] = i , id[i] = cnt ;        for(int j = 1 ; j <= cnt && i * prime[j] <= up ; j   )        {            vis[i * prime[j]] = 1 ;            if(i % prime[j] == 0) break ;        }    }}vector<int> v[700000   10] ;void init(int x , int c){    int now = 1 ;    for(int i = 1 ; prime[i] * prime[i] <= x ; i   )    {        if(x % prime[i] == 0)          {            while(x % prime[i] == 0)  x /= prime[i] ;            now *= prime[i] ;            v[i].push_back(c) ;        }    }    if(x > 1)  v[id[x]].push_back(c) ;}int head[maxn] ;int num = 1 ;int dfn[maxn] , low[maxn] , parent[maxn];int ans = 0 ;int cut[maxn] ;struct Node{    int v , next ;} edge[maxn] ;void add(int u , int v){    edge[num].v = v ;    edge[num].next = head[u] ;    head[u] = num    ;}void add1(int u , int v){    add(u , v) ;    add(v , u) ;}void dfs(int u){    static int count = 0 ;    int children = 0 ;    int v ;    dfn[u] = low[u] =    count ;    for(int i = head[u] ; i != 0 ; i = edge[i].next)    {        v = edge[i].v ;        if (dfn[v] == 0)        {            children    ;            parent[v] = u ;            dfs(v) ;            low[u] = min(low[u] , low[v]) ;            if(cut[u] == 0 && (parent[u] == -1 && children >= 2 || parent[u] != -1 && low[v] >= dfn[u]))            {                ans    ;                cut[u] = 1 ;                //cout << u << '\n' ;                      }                    }        else if (v != parent[u])        low[u] = min(low[u], dfn[v]) ;    }}int main(){    std::ios::sync_with_stdio(false) , cin.tie(0) ;    get_prime(10000000) ;    int n ;    cin >> n ;    for(int i = 0 ; i < n ; i   )    {        int x ;        cin >> x ;        init(x , i   1) ;    }    memset(head , 0 , sizeof(head)) ;    memset(parent , -1 , sizeof(parent)) ;    memset(dfn , 0 , sizeof(dfn)) ;    for(int i = 1 ; i <= cnt ; i   )    {        int siz = v[i].size() ;        if(siz >= 2)        {            for(int j = 0 ; j < siz - 1 ; j   )                add1(v[i][j] , v[i][j   1]) ;            add1(v[i][0] , v[i][siz - 1]) ;        }    }    for(int i = 1 ; i <= n ; i   )        if(dfn[i] == 0)  dfs(i) ;    cout << ans << '\n' ;    return 0 ;}

F  小G的排列

留坑。

来源:https://www.icode9.com/content-4-871701.html

(0)

相关推荐