zoukankan      html  css  js  c++  java
  • [考试总结]ZROI-21-CSP7连-DAY4 总结

    #T1 扫雷

    #题意简述

    一个 (n imes m(n,mleq200)) 的网格,每个格子中的数字表示以该格子为中心的 (3 imes3) 的方格中地雷的数量,问总共有多少个地雷。

    #大体思路

    我们不需要知道地雷具体怎么摆放,所以只要找到一组点各自的势力范围能恰好覆盖整张地图即可,于是我们可以直接上下、左右各相隔三个进行选点。

    #Code

    const int N = 210;
    
    int n, m, a[N][N], ans;
    
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; ++ i)
          for (int j = 1; j <= m; ++ j)
            scanf("%d", &a[i][j]);
        /*特别注意填充开始的边界*/
        for (int i = n % 3 ? 1 : 2; i <= n; i += 3)
          for (int j = m % 3 ? 1 : 2; j <= m; j += 3)
            ans += a[i][j];
        printf("%d", ans);
        return 0;
    }
    

    #T2 翻转

    #题意简述

    有一个 (n imes m(n,mleq100)) 的 01 矩阵,现在需要将所有位置变为 (1),改变的规则如下:

    • 对于 ((a,b)),若 (exists xin[1,n],yin[1,m]),其中 ((a,y),(x,b),(x,y)) 均为 (1),那么修改 ((a,b)) 的代价为 (3),否则为 (4).

    问最小代价。

    #大体思路

    考虑如何判断是否 (exists xin[1,n],yin[1,m]),其中 ((a,y),(x,b),(x,y)) 均为 (1),不难发现,如果将 ((i,j)=1) 看作将第 (i) 行((L.i))和第 (j) 列((A.j))连接的话,那么意味着 (L.a,L.x,A.b,A.y) 应当在同一连通块内,而最终的状态一定有全图为一个连通块,于是我们一定需要将所有初始连通块连成一块,这需要以 (4) 的代价修改连通块数量减 (1) 个点,最后剩下的点的修改代价都为 (3).

    #Code

    const int N = 100010;
    const int INF = 0x3fffffff;
    
    /*用并查集维护连通块信息*/
    struct DSU {
        int siz[N], f[N], tot;
    
        inline void init(int x) {
            tot = x;
            for (int i = 0; i <= x; ++ i)
              f[i] = i, siz[i] = 1;
        }
    
        inline int find(int x) {
            while (x != f[x]) x = f[x] = f[f[x]];
            return x;
        }
    
        inline void merge(int x, int y) {
            x = find(x), y = find(y);
            if (x == y) return;
            if (siz[x] > siz[y]) swap(x, y);
            f[x] = y, siz[y] += siz[x], -- tot;
        }
    } dsu;
    
    int n, m, tcnt, ans; char c;
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> n >> m; dsu.init(n + m);
        for (int i = 1; i <= n; ++ i)
          for (int j = 1; j <= m; ++ j) {
            cin >> c; if (c == '1') dsu.merge(i, j + n), ++ tcnt;
          }
        ans = (dsu.tot - 1) * 4 + (n * m - tcnt - dsu.tot + 1) * 3;
        cout << ans; return 0;
    }
    

    #T3 斜率

    #题意简述

    平面直角坐标系上 (n(nleq10^6)) 个点,可任选 (2) 个点连直线,找到斜率最接近 (frac P Q) 的直线的斜率。

    #大体思路

    我们考虑有一条斜率为 (frac PQ) 的直线在坐标系上平移,我们可以得到所有点按此方向在 (x) 轴上的投影,不难发现,斜率最接近 (frac PQ) 的两个点的投影一定相邻,这一点简单画图不难发现,于是我们直接按照投影位置进行排序即可。

    #Code

    #define db double
    #define ll long long
    
    const int N = 1000010;
    const db INF = 1e10;
    
    template <typename T> inline T ABS(const T &x) {return x < 0 ? -x : x;}
    
    double tana, ans_gap = INF;
    int n; ll p, q, nx, ny;
    
    struct Point {
        ll x, y;
        bool operator < (const Point & b) const {
            return -x * p + y * q < -b.x * p + b.y * q;
        }
    } a[N];
    
    ll gcd(ll x, ll y) {return y ? gcd(y, x % y) : x;}
    
    db calc(Point x, Point y) {
        return x.x == y.x ? INF : (db)(x.y - y.y) / (db)(x.x - y.x); 
    }
    
    int main() {
        scanf("%d%lld%lld", &n, &p, &q);
        tana = (db)p / (db)q;
        for (int i = 1; i <= n; ++ i)
          scanf("%lld%lld", &a[i].x, &a[i].y);
        sort(a + 1, a + n + 1);
        for (int i = 1; i < n; ++ i) {
            db now_gap = ABS(calc(a[i], a[i + 1]) - tana);
            if (now_gap < ans_gap) {
                ans_gap = now_gap;
                nx = ABS(a[i].x - a[i + 1].x);
                ny = ABS(a[i].y - a[i + 1].y);
            }
        }
        ll g = gcd(ny, nx);
        printf("%lld/%lld", ny / g, nx / g);
        return 0;
    }
    

    #T4 任务

    #题意简述

    (n(nleq 350)) 个人和 (n)不同的任务,第 (i) 个人高兴当且仅当他被分到 (i) 个任务,问将所有任务都分配下去后至少有一个人高兴的方案数((mod10^9+7))。

    #大体思路

    这种计数问题还是要去尝试 DP,设 (f_{i,j}) 表示前 (i) 个人分 (j) 个任务,至少有 (1) 个人高兴的方案数,考虑第 (i) 个人是否高兴。

    (i) 个人高兴,则可以挑出 (i) 个直接给第 (i) 个人,剩下的 (j-i) 个可以随意的给 (i-1) 个人,于是方案总数为 (dbinom jicdot(i-1)^{j-i})

    如果第 (i) 个人不高兴,那么设给了第 (i) 个人 (k(k e i)) 个任务,那么此时的方案数为前 (i-1) 个人分 (j-k) 个的方案数,于是该情况的总方案数为

    [sumlimits_{k=1}^n[k e i]dbinom jkf_{i-1,j-k}, ]

    #Code

    #define ll long long
    
    const int N = 510;
    const int MOD = 1e9 + 7;
    const int INF = 0x3fffffff;
    
    int n; ll C[N][N], f[N][N];
    
    inline void init_C(int x) {
        for (int i = 0; i <= x; ++ i) C[i][0] = C[i][i] = 1;
        for (int i = 1; i <= x; ++ i)
          for (int j = 1; j < i; ++ j)
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
    }
    
    ll fpow(ll a, ll b) {
        ll res = 1;
        while (b) {
            if (b & 1) (res *= a) %= MOD;
            (a *= a) %= MOD, b >>= 1;
        }
        return res;
    }
    
    int main() {
        scanf("%d", &n); init_C(n);
        for (int i = 1; i <= n; ++ i)
          for (int j = 0; j <= n; ++ j) {
              if (j >= i) f[i][j] = fpow(i - 1, j - i) * C[j][i] % MOD;
              for (int k = 0; k <= j; ++ k) {
                  if (k == i) continue;
                  (f[i][j] += f[i - 1][j - k] * C[j][k] % MOD) %= MOD;
              }
          }
        printf("%lld", f[n][n]);
        return 0;
    }
    
  • 相关阅读:
    MySQL数据库之WHERE条件语句
    MySQL数据库的简单操作指令之DML语言
    课程设计必备之数据库操作代码模板
    MySQL数据库之外键约束的简单理解
    pdf.js的使用
    javascript连连看
    数据库问题
    列表文字超出后,鼠标悬浮显示全部内容
    springboot component注入servecie
    点击列表 获取table tr td 下的input value
  • 原文地址:https://www.cnblogs.com/Dfkuaid-210/p/ZROI-21-CSP-DAY4.html
Copyright © 2011-2022 走看看