• AtCoder Beginner Contest 248 赛时记录


    手速场。手速场。手速场。手速场。手速场。

    上大分。上大分。上大分。上大分。上大分。

    A - Lacked Number

    随便标记看看哪个数没出现过,或者拿 \(45\) 去把所有数减掉剩下的数就是。

    B - Slimes

    暴力乘,算次数

    C - Dice Sum

    简单 DP。

    \(f_{i,j}\) 表示前 \(i\) 个数的和为 \(j\) 的方案数。

    \[f_{i,j} = \sum_{k=1}^{m} f_{i-1,j-k} \]

    D - Range Count Query

    对每个颜色开一个 vector,然后存出现的位置。

    对于每次询问直接在对应 vectorupper_bound 出和合法的左右端点相减就能得到答案。

    signed main() {
        n = read();
        for(int i = 1; i <= n; ++i) {
            a[i] = read();
            b[a[i]].push_back(i);
        }
        Q = read();
        for(int i = 1, l, r, x; i <= Q; ++i) {
            l = read(), r = read(), x = read();
            int L = upper_bound(b[x].begin(), b[x].end(), l - 1) - b[x].begin() - 1;
            int R = upper_bound(b[x].begin(), b[x].end(), r) - b[x].begin() - 1;
            cout << R - L << "\n";
        }
    	return 0;
    }
    

    E - K-colinear Line

    枚举两个点确定一条直线,然后枚举第三个点判断有多少点在这个直线上。

    判断直线的方式我们采用向量的形式,\(i,j,k\) 三个点可以得到两个向量 \((a,b) = (x_i-x_k,y_i-y_k), (c,d) = (x_j-x_k,y_j-y_k)\),那如果 \(ad=bc\) 就说明这三个点在一条直线上。

    然后发现这样会算重很多。

    对于一条有 \(K\) 个点的直线来说,会被算重 \(\frac{K(K-1)}{2}\),所以统计 \(K\) 个点的直线有几条,计算贡献的时候除以 \(\frac{K(K-1)}{2}\) 就好了。

    bool Check(int i, int j, int k) {
        int ax = x[i] - x[k], ay = y[i] - y[k];
        int bx = x[j] - x[k], by = y[j] - y[k];
        return ax * by == ay * bx;
    }
    
    signed main() {
        n = read(), K = read();
        if(K == 1) { return puts("Infinity"), 0; }
        for(int i = 1; i <= n; ++i) x[i] = read(), y[i] = read();
        for(int i = 1; i <= n; ++i) {
            for(int j = i + 1; j <= n; ++j) {
                int res = 2;
                for(int k = 1; k <= n; ++k) {
                    if(k == i || k == j) continue;
                    if(Check(i, j, k)) res ++;
                }
                cnt[res] ++;
            }
        }
        for(int i = K; i <= n; ++i) ans += cnt[i] * 2 / i / (i - 1);
        cout << ans << "\n";
    	return 0;
    }
    

    F - Keep Connect

    考虑直接 DP。

    一开始的一个想法是设 \(f_{i,j,0/1}\) 表示前 \(i\) 列删了 \(j\) 条边第 \(i\) 列中间那条边删没删,然后发现你转移的时候不知道最后的结果合不合法,因为不知道连通性,所以把意义换一下,改成表示前 \(i\) 列删了 \(j\) 条边是否联通的方案数。

    然后在打草纸上画一下所有情况进行转移即可。

    最后可以得出:

    初始化 \(f_{1,0,1} = f_{1,1,0} = 1\)

    \[\begin{aligned} f_{i,j,1} & = f_{i-1,j,1} + 3 f_{i-1,j-1,1} + f_{i-1,j,0} \\ f_{i,j,0} & = f_{i-1,j-1,0} + 2 f_{i-1,j-2,1} \end{aligned} \]

    答案就是 \(f_{n,i,1}\)

    signed main() {
        n = read(), P = read();
        f[1][0][1] = 1, f[1][1][0] = 1;
        for(int i = 1; i <= n; ++i) {
            for(int j = 0; j <= n - 1; ++j) {
                f[i][j][1] += f[i - 1][j][1];
                if(j > 0) f[i][j][1] += f[i - 1][j - 1][1] * 3;
                f[i][j][1] += f[i - 1][j][0];
                if(j > 0) f[i][j][0] += f[i - 1][j - 1][0];
                if(j > 1) f[i][j][0] += f[i - 1][j - 2][1] * 2;
                f[i][j][1] %= P, f[i][j][0] %= P;
            }
        }
        for(int i = 1; i <= n - 1; ++i) {
            cout << f[n][i][1] << " ";
        }
    	return 0;
    }
    

    G - GCD cost on the tree

    给你一棵大小为 \(n\) 的树,点有点权,求

    \[\sum_{i=1}^{n} \sum_{j=i+1}^{n} dis(i,j) \times \gcd(a_{p_k}) \]

    \(dis(i,j)\) 表示 \(i \to j\) 的路径长,\(\gcd(a_{p_k})\) 表示路径经过的点的权值的 \(\gcd\)

    \(2 \le n \le 10^5, 1 \le a_i \le 10^5\)

    众所周知 \(\sum_{d | n} \varphi (d) = n\)

    所以上式可转化为

    \[\sum_{i=1}^{n} \sum_{j=i+1}^{n} dis(i,j) \times \sum_{d | \gcd(a_{p_k})} \varphi(d) \]

    \(d\) 提到外面得到

    \[\sum_{d} \varphi(d) \sum_{i=1}^{n} \sum_{j=i+1}^{n} dis(i,j) \times [d | \gcd(a_{p_k})] \\ \]

    所以我们可以枚举外面的 \(d\),然后只取 \(d | a_i\) 的点,在这些点所构成的森林中计算出两两距离的和,就可以得到后面这一块的贡献,两两距离的和可以通过两次 dfs 得到。

    寻找 \(a_i\) 的因数的复杂度是 \(\sqrt {a_i}\) ,因为 \(10^5\) 内的数的因子最多有 \(128\) 个,所以枚举 \(d\) 求贡献的复杂度最多是 \(128n\) 的。

    所以总复杂度为 \(n \sqrt {a_i} + 128n\),可以通过。

    #include<bits/stdc++.h>
    #define LL long long
    #define int long long
    #define orz cout << "tyy YYDS!!!\n"
    using namespace std;
    const int MAXN = 2e5 + 10;
    const int INF = 1e9 + 7;
    const int mod = 998244353;
    
    int n, D, res, ans = 0;
    int a[MAXN], siz[MAXN];
    vector<int> E[MAXN], V[MAXN];
    bool vis[MAXN];
    
    int read() {
    	int s = 0, f = 0; char ch = getchar();
    	while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
    	while(isdigit(ch)) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    	return f ? -s : s;
    }
    
    void dfs1(int u, int fa) {
        vis[u] = true, siz[u] = 1;
        for(auto v : E[u]) {
            if(v == fa) continue;
            if(a[v] % D) continue;
            dfs1(v, u);
            siz[u] += siz[v];
        }
    }
    
    void dfs2(int u, int fa, int sz) {
        vis[u] = false;
        int lst = sz - siz[u] + 1;
        res += lst;
        for(auto v : E[u]) {
            if(v == fa || a[v] % D) continue;
            res = (res + lst * siz[v] % mod) % mod;
            lst += siz[v];
        }
        for(auto v : E[u]) {
            if(v == fa || a[v] % D) continue;
            dfs2(v, u, sz);
        }
    }
    
    int Phi(int x) {
        int res = 1;
        for(int i = 2; i * i <= x; ++i) {
            if(x % i) continue;
            res *= (i - 1);
            x /= i;
            while(x % i == 0) res *= i, x /= i;
        }
        if(x > 1) res = res * (x - 1);
        return res;
    }
    
    signed main() {
        n = read();
        for(int i = 1; i <= n; ++i) a[i] = read();
        for(int i = 1; i <= n; ++i) {
            int x = a[i];
            for(int j = 1; j * j <= a[i]; ++j) {
                if(a[i] % j) continue;
                V[j].push_back(i);
                if(j * j != a[i]) V[a[i] / j].push_back(i);
            }
        }
        for(int i = 1, u, v; i < n; ++i) { 
            u = read(), v = read();
            E[u].push_back(v), E[v].push_back(u);
        }
        for(D = 1; D <= 100000; ++D) {
            res = 0;
            for(auto u : V[D]) if(!vis[u]) dfs1(u, 0);
            for(auto u : V[D]) if(vis[u]) dfs2(u, 0, siz[u]); 
            ans = (ans + Phi(D) * res % mod) % mod;
        }
        for(int i = 1; i <= n; ++i) ans = (ans - a[i] + mod) % mod;
        printf("%lld\n", ans);
    	return 0;
    }
    
  • 相关阅读:
    Java_Activiti5_菜鸟也来学Activiti5工作流_之入门简单例子(一)
    Java_Activiti5_菜鸟也来学Activiti5工作流_之初识BPMN2.0的简单结构(五)
    Java_Activiti5_菜鸟也来学Activiti5工作流_之JUnit单元测试(四)
    Java_Activiti5_菜鸟也来学Activiti5工作流_之与Spring集成(三)
    Java_Activiti5_菜鸟也来学Activiti5工作流_之初识常用服务类和数据表(二)
    Html+Css+Js_之table每隔3行显示不同的两种颜色
    Java使用poi对Execl简单操作_总结
    Java使用poi对Execl简单_写_操作
    Java使用poi对Execl简单_读_操作
    Java使用poi对Execl简单_读和写_操作
  • 原文地址:https://www.cnblogs.com/Silymtics/p/ABC248.html
Copyright © 2020-2023  润新知