AtCoder ABC 131

C - Anti-Division(ATC经典题型 + lcm)

Description:

​ 给你一段区间[a, b] (<= 1e18),请问区间中有多少数字是满足又不被c整除,又不被d整除

Solution:

​ 由于区间范围大,不可能暴力枚举。我们直接容斥一下,找区间中被c整除和被d整除的个数

​ 容易想到用区间长度分别除c和d得到个数,但是仅仅对[1, x]能这样做,我们就用一下前缀和的思想[a, b] = [1, b] - [1, a - 1]就好,发现样例过不了,观察发现原来是发生了重复计算,比如2和3都被6整除,本来贡献应该为1,但是这样算的话,贡献为2了。我们就找一下c和d的最小公倍数,然后得到区间中重复计算过的被lcm的倍数所整除的个数,减去这个数就是正解了

Code:

int main()
{
    cin >> a >> b >> c >> d;
    LL res1 = b - (b / c + b / d - b / lcm(d, c));
    LL res2 = (a - 1) - ((a - 1) / c + (a - 1) / d - (a - 1) / lcm(d, c));
    cout << res1 - res2;
}




E - Friendships(图论 + 构造)

Description:

​ 给出n和k,表示无向联通图中有n个点,你可以任意连边,输出能构造出k条两点间最短路为2的图的连边方案。

Solution:

​ 需要从图的性质入手,无向连通图意味着图中最少需要有n - 1条边才能保证联通。如果连接一条边的话,对两个端点的影响就是使两个端点的最短路长度为1了。可以推得:边数越多,最短路长度为2的路越少。考虑一种卫星式的连接方案,此时最短路为2的边数有(n - 1) * (n - 2) / 2条,这是k的最大值,若k大于该值,必然不可能构成,在这个方案的基础上,我们来减少最短路为2的路的数量。由于连接一条边,可以使两个端点最短路长度为1,我们就找两个最短路长度为2的端点来连接。为了便于输出不同的方案,从1和其他边开始连边,连到n - 1的时候,将1变成2继续连边,以此类推。

Code:

int n, k;
struct node {
    int u, v;
    node(){}
    node(int a, int b):u(a), v(b){}
};
vector<node> g;

int main()
{
    cin >> n >> k;
    int m = (n - 1); //若要保证图的连通性,最少需要n - 1条边 
    //因为一条边会使一条路径长度变成1 所以边越多 长度为2的路径越少
    if(n == 0)
    {
        cout << -1;
        return 0;
    }

    int sum = m * (m - 1) / 2; //以一个点为中心点,其他店全部直接与其相连,可以得到最多的长度为2的边数
    if(k > sum)
    {
        cout << -1;
        return 0;
    }
    for(int i = 1; i <= m; i ++)
        g.push_back(node(i, n)); //(n - 1)(n - 2) / 2条边
    
    int i = 1, j = 2;
    while(sum != k) //连一条边,减少一个答案
    {
        sum --;
        g.push_back(node(i, j));
        j ++;
        if(j == m + 1)  i ++, j = i + 1;
    }

    cout << g.size() << '\n';
    for(auto x : g)
        cout << x.u << ' ' << x.v << '\n';
}

你可能感兴趣的:(AtCoder,算法,图论,数据结构)