noip6 &&多校1

11.12

t1

\(O(nm^2)\)是简单的。

发挥人类智慧发现每次最优只在前面较少的状态。

于是可过。

其实人类智慧有证明的。

考虑若最大值越大,则选的次数越小,反之亦然。

平均一下就过了。

code

t1
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
const int M = 5e3 + 10;
int n, m;
int a[N], b[N], pos[M];
int dp[N][M];

signed main()
{
    freopen("crazy.in", "r", stdin);
    freopen("crazy.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        cin >> a[i], b[i] = a[i];
    sort(b + 1, b + 1 + n);
    for (int i = 0; i <= m; ++i)
        pos[i] = upper_bound(b + 1, b + 1 + n, i) - b - 1;

    memset(dp, 0x3f, sizeof(dp));
    dp[0][0] = 0;
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 0; j <= m; ++j)
            for (int k = max(j - 100, 0); k <= j; ++k)
                dp[i][j] = min(dp[i][j], dp[i - 1][k] + n - pos[j - k]);
    }
    cout << dp[n][m];
    return 0;
}

t2

dp加一吨特判。

赛事困+左右脑互搏,写了个抽象东西dfs。

本质就是dp中的一种转移,我也不知道为啥写个dfs转移。

code

t2
#include <bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int T, n, m;
int a[N][N], dp[N][N];

int val(int x, int y, int c, int d)
{
    if (a[x][y] ^ a[c][d])
        return (a[c][d] && !a[x][y]);
    else
        return 0;
}

inline void solve()
{
    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            cin >> a[i][j];
    if ((n == 1 && m == 1 && a[1][1]) || (n * m == 2 && (a[1][1] ^ a[n][m])))
    {
        cout << "Impossible\n";
        return;
    }
    
    if (n == 1)
    {
        int tot = 0, lst = 0;
        for (int i = 1; i <= m; ++i)
        {
            if (a[1][i])
                lst = i, ++tot;
            dp[1][i] = dp[1][i - 1] + val(1, i - 1, 1, i);
        }
        if (tot == 1)
            dp[n][m] = 2 + ((lst - 1) <= 1 && (m - lst) <= 1);
        cout << dp[n][m] << "\n";
        return;
    }

    if (m == 1)
    {
        int tot = 0, lst = 0;
        for (int i = 1; i <= n; ++i)
        {
            if (a[i][1])
                lst = i, ++tot;
            dp[i][1] = dp[i - 1][1] + val(i - 1, 1, i, 1);
        }
        if (tot == 1)
            dp[n][m] = 2 + ((lst - 1) <= 1 && (n - lst) <= 1);
        cout << dp[n][m] << "\n";
        return;
    }

    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= m; ++j)
        {
            if (i == 1 && j == 1)
                dp[i][j] = a[i][j];
            else if (i == 1)
                dp[i][j] = dp[i][j - 1] + val(i, j - 1, i, j);
            else if (j == 1)
                dp[i][j] = dp[i - 1][j] + val(i - 1, j, i, j);
            else
                dp[i][j] = min(dp[i][j - 1] + val(i, j - 1, i, j), dp[i - 1][j] + val(i - 1, j, i, j));
        }
    }

    cout << dp[n][m] << "\n";
}

signed main()
{
    freopen("flip.in", "r", stdin);
    freopen("flip.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> T;
    while (T--)
        solve();
    return 0;
}

t3

你直接出那个ds都是吉司机线段树。

然后还变成神秘东西???

神人题,神人做。

t4

如果发现了是最短路就可以秒。

相邻两个非冰的块次数为2。

每次向上下左右扩展到的第一个冰的之前的块次数为1(单向边)。

然后dij即可。

code

t4
#include <bits/stdc++.h>
#define pir pair<int, int>
#define fi first
#define se second
using namespace std;
const int N = 1e3 + 10;
int n, m, x1, y3, x2, y2;
vector<pir> e[N * N];
char c[N][N];
int dis[N * N];
bool flag[N * N];
priority_queue<pir, vector<pir>, greater<pir>> q;

inline int get_id(int i, int j) { return (i - 1) * m + j; }

inline void dij(int op)
{
    memset(dis, 0x3f, sizeof(dis));
    memset(flag, 0, sizeof(flag));
    dis[op] = 0;
    q.push(make_pair(0, op));
    while (q.size())
    {
        int x = q.top().se;
        q.pop();
        if (flag[x])
            continue;
        flag[x] = 1;
        for (auto y : e[x])
        {
            if (dis[y.fi] > dis[x] + y.se)
            {
                dis[y.fi] = dis[x] + y.se;
                q.push(make_pair(dis[y.fi], y.fi));
            }
        }
    }
}

signed main()
{
    freopen("skate.in", "r", stdin);
    freopen("skate.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            cin >> c[i][j];

    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
        {
            if (c[i][j] == '#')
                continue;
            if (c[i - 1][j] == '.')
                e[get_id(i, j)].emplace_back(make_pair(get_id(i - 1, j), 2));
            if (c[i][j - 1] == '.')
                e[get_id(i, j)].emplace_back(make_pair(get_id(i, j - 1), 2));
            if (c[i + 1][j] == '.')
                e[get_id(i, j)].emplace_back(make_pair(get_id(i + 1, j), 2));
            if (c[i][j + 1] == '.')
                e[get_id(i, j)].emplace_back(make_pair(get_id(i, j + 1), 2));

            int nx = i, ny = j;
            while (c[nx][ny] == '.') // up
                --nx;
            ++nx;
            if (!(nx == i && ny == j))
                e[get_id(i, j)].emplace_back(make_pair(get_id(nx, ny), 1));

            nx = i, ny = j;
            while (c[nx][ny] == '.') // left
                --ny;
            ++ny;
            if (!(nx == i && ny == j))
                e[get_id(i, j)].emplace_back(make_pair(get_id(nx, ny), 1));

            // cout << "nx=" << nx << " ny=" << ny << "\n";

            nx = i, ny = j;
            while (c[nx][ny] == '.') // down
                ++nx;
            --nx;
            if (!(nx == i && ny == j))
                e[get_id(i, j)].emplace_back(make_pair(get_id(nx, ny), 1));

            // cout << "nx=" << nx << " ny=" << ny << "\n";
            nx = i, ny = j;
            while (c[nx][ny] == '.') // right
                ++ny;
            --ny;
            if (!(nx == i && ny == j))
                e[get_id(i, j)].emplace_back(make_pair(get_id(nx, ny), 1));
        }
    cin >> x1 >> y3 >> x2 >> y2;
    dij(get_id(x1, y3));
    cout << (dis[get_id(x2, y2)] > 100000000 ? -1 : dis[get_id(x2, y2)]);
    return 0;
}

紧急写的(10min),仓促。

posted @ 2025-11-12 22:08  HS_fu3  阅读(25)  评论(4)    收藏  举报