牛客小白月赛75 D~E

发布时间 2023-07-06 11:46:18作者: wuyoudexian

D. 矩阵

D-矩阵_牛客小白月赛75 (nowcoder.com)

题意

\(n\times m\)大小的矩阵,每个元素可能是字符'0'或'1',从起点(1,1)开始,可以上下左右移动,如果移动前后位置的字符不同,则花费一个单位时间,否则,需要花费一个单位时间把移动后位置的字符更改,再花费一个单位时间移动。求走到(n,m)最少需要多少单位时间。

思路

用Dijkstra算法求最短路,图分为两层,一层元素全是'0',一层元素全是'1'。每次移动就是从一层图调到另一层图,如果移动前后位置的元素不同,则权值为1,否则权值为2。

代码

#include<bits/stdc++.h>

using namespace std;
using ll = long long;
const int inf = 0x3f3f3f3f;
const int N = 1005;

struct node {
    int x, y, k, dis;
    bool operator <(const node &a) const {return dis > a.dis;}
};

array<array<array<int, 2>, N>, N> dis;
array<array<array<bool, 2>, N>, N> vis;
array<int, 4> dx = {1, 0, -1, 0}, dy = {0, 1, 0, -1};
priority_queue<node> q;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;

    vector<string> s(n + 1);
    for(int i = 1; i <= n; i++) {
        cin >> s[i];
        s[i] = " " + s[i];
    }

    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            dis[i][j][1] = dis[i][j][0] = inf;
        }
    }

    dis[1][1][s[1][1]-'0'] = 0;
    q.push({1, 1, s[1][1] - '0'});
    while(!q.empty()) {
        int x = q.top().x,
            y = q.top().y,
            k = q.top().k;
        q.pop();
        if(vis[x][y][k]) continue;
        vis[x][y][k] = true;
        for(int i = 0; i < 4; i++) {
            int tx = x + dx[i],
                ty = y + dy[i];
            if(tx < 1 || tx > n || ty < 1 || ty > m) continue;
            if(dis[tx][ty][k^1] > dis[x][y][k] + 1 + (s[tx][ty] - '0' == k)) {
                dis[tx][ty][k^1]  = dis[x][y][k] + 1 + (s[tx][ty] - '0' == k);
                q.push({tx, ty, k ^ 1, dis[tx][ty][k^1]});
            }
        }
    }

    cout << min(dis[n][m][0], dis[n][m][1]) << "\n";
   
    return 0;
}

E. 数数

题意

如果长为\(n\)一个数组\(a\)满足以下条件,则其称美好数组。
1. 对于\(1\le i\le n\),满足\(1\le a_i\le m\)
2. 对于\(1\le i\le n\),满足\(\sum_{j=1}^i a_i\)\(i\)的倍数。

思路

\(dp[i][j]\)为前\(i\)个数,和为\(i\times j\)的状态,则有\(i\times j_1-(i-1)\times j_2\le m\)\(j_2\)从大到小枚举,直到不满足该不等式。

代码

#include<bits/stdc++.h>

using namespace std;
using ll = long long;
const int mod = 1e9 + 7;
const int N = 2005;

array<array<int, N>, N> dp;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;

    dp[0][1] = 1;

    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            int f = (i == 1) ? 1 : i * j / (i - 1);
            f = min(f, m);
            if(f * (i - 1) == i * j) {
                f -= 1;
            }
            while(f > 0 && i * j - (i - 1) * f <= m) {
                dp[i][j] = (dp[i][j] + dp[i-1][f]) % mod;
                f--;
            }
        }
    }

    ll ans = 0;
    for(int i = 1; i <= m; i++) {
        ans = (ans + dp[n][i]) % mod;
    }

    cout << ans << "\n";
   
    return 0;
}