2025十一集训——Day1模拟赛

原题

赛前

6:40

为了模拟赛早起

7:00

开坑,还不知道密码是啥。

我是乐子点错比赛了,没有密码

赛时

(赛时忘写了,赛后补qwq)

T1 水题,切了。

T2 想到正解写了个拓扑排序,有环炸了,以为要缩点跑了

T3 感觉有头绪,竟然场切了!!!

T4 不会,写个暴力跑了。

T3做出后不想冲部分分,遂跑。

最终:100 + 0 + 100 + 0。

赛后

全tm是原。

两黄两紫。

这 T2 咋过了一车?

艹直接 Dfs 加个层数判断,n tm 就 100,\(O(n^3)\) 直接乱搞都行,成小丑了。

明显问题:对题目难度没有有效判断(但是帮助我切 T3 了,要是知道这是个紫都不敢写),以及 whk 过久码力和思维很弱……

菜就多练

题解

A。

https://www.luogu.com.cn/problem/P9939

题意,二维矩阵,有草、牛、空地,一个草可以给相邻两头牛配对,但一个草只能勇一次,两头牛只能配一次,但一头牛能和多头牛配,问最多配几对。

那显然直接枚举每个草,先横竖(不会产生重复)在斜,判一下 2 * 2 对角线(牛会配两次,要减一),没了。

SB 签到。

代码:
`

点击查看代码
#include <bits/stdc++.h>
#define dbg(x) cout << #x << '=' << x << endl
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define frep(i, r, l) for (int i = (r); i >= (l); i--)
//#define int long long
using namespace std;

const int N = 1010;

int n, m, ans;
char s[N][N];
bool f[N][N];


void work()
{
    cin >> n >> m;
    rep(i, 1, n) cin >> s[i] + 1;
    rep(i, 1, n) {
        rep(j, 1, m) {
            if (s[i][j] != 'G') continue;
            if ((s[i - 1][j] == 'C' && s[i + 1][j] == 'C') || (s[i][j - 1] == 'C' && s[i][j + 1] == 'C')) ans++;
            else {
                if (s[i - 1][j] == 'C' && s[i][j - 1] == 'C' && !f[i - 1][j - 1]) {
                    ans++, f[i][j] = 1;
                }
                else if (s[i - 1][j] == 'C' && s[i][j + 1] == 'C' && !f[i - 1][j + 1]) {    
                    ans++, f[i][j] = 1;
                }
                else if (s[i + 1][j] == 'C' && s[i][j - 1] == 'C' && !f[i + 1][j - 1]) {
                    ans++, f[i][j] = 1;
                }
                else if (s[i + 1][j] == 'C' && s[i][j + 1] == 'C' && !f[i + 1][j + 1]) {
                    ans++, f[i][j] = 1;
                }                
            }
        }
    }

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

int main()
{
    // freopen("friend.in", "r", stdin);
    // freopen("friend.out", "w", stdout);
    std::ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T = 1, opinput = 0;
    if (opinput) cin >> T;
    while (T--) work();
    return 0;
}
`

B

https://www.luogu.com.cn/problem/P8268

题意,每种金属都能由其他两种金属个 1g 来得到 1g,问得到 1 号的最大数量。

其实很好写,我赛时为什么会写 SB 拓扑处理环啊啊啊。

二分答案。

对于一个点,假设我们需要 lim 个,现在有 a 个,若 \(a>=lim\) 直接满足,否则要让 ls 和 rs 有 \(b>=lim\) 个,递归 Check,没了。

然后有环的话直接无解,因为走一遍环相当于取了一堆 min,显然不优,然后因为 \(n<=100\) 跑遍环也 T 不了,直接写。

就这么水 f**k。

点击查看代码
#include <bits/stdc++.h>
#define dbg(x) cout << #x << '=' << x << endl
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define frep(i, r, l) for (int i = (r); i >= (l); i--)
#define int long long
using namespace std;

const int N = 105;

int n, now, ls[N], rs[N];
int a[N], b[N], vis[N];


bool Dfs(int x, int k) {
    if (b[x] >= k) {b[x] -= k; return 1;}
    vis[x] = 1; k -= b[x], b[x] = 0;
    if (vis[ls[x]] || !Dfs(ls[x], k)) return 0;
    if (vis[rs[x]] || !Dfs(rs[x], k)) return 0;
    vis[x] = 0; return 1;
}

void work()
{
    cin >> n;
    int l = 1, r = 0, ans = 0;
    rep(i, 1, n) cin >> ls[i] >> rs[i];
    rep(i, 1, n) cin >> a[i], r += a[i];
    l = a[1];
    while (l <= r) {
        int mid = l + r >> 1;
        rep(i, 1, n) vis[i] = 0, b[i] = a[i];
        if (Dfs(1, mid)) ans = mid, l = mid + 1;
        else r = mid - 1;
    }
    cout << "Case #" << (++now) << ": " << ans << "\n";
}

signed main()
{
    freopen("alchemy.in", "r", stdin);
    freopen("alchemy.out", "w", stdout);
    std::ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T = 1, opinput = 1;
    if (opinput) cin >> T;
    while (T--) work();
    return 0;
}

C:

https://www.luogu.com.cn/problem/P7967

P7967 [COCI 2021/2022 #2] Magneti

题目描述

给定 \(n\) 个磁铁和 \(l\) 个空位,其中相邻空位之间的距离为 \(1\),每个空位可放置一个磁铁。所有 \(n\) 个磁铁都必须被放置。每个磁铁可以吸引距离小于 \(r_i\) 的其它磁铁。求所有磁铁互不吸引的方案总数对 \(10^9+7\) 取模的结果。

首先考虑把这些磁铁以某种排列排好,并紧密相连(卡着 r 放置),设这一大段长为 \(k\),根据插板法有 \(C^{n}_{l-k+n}\)

所以转化为求 \(f_k:\) 长度为 \(k\) 的磁铁排列有多少。

起初我设计的是 \(f_{i, k}\)\(i\) 个磁铁长度为 \(k\) 的排列,转移直接 \(f_{i, k} \to f_{i+1, k+r_i}\),但是你不知道插到中间有多少可能,显然炸了。

考虑上一个做法失败是因为不知道那些磁铁之间有空,那么再加一位,而且根据数据范围大概是 \(O(n^2*l)\),所以设计 \(f_{i,j,k}\) 使前 \(i\) 个磁铁分成 \(j\) 个段(段之间不能放入磁铁),所有段的长度之和为 \(k\)。(段之间没有顺序,不考虑间隔)

首先把 \(r\) 排序,这样后面大一定放不到前面小的,使限制弱化,然后考虑转移:

  • 直接开一段:\(f_{i,j,k}\to f_{i+1,j+1,k}\)
  • 插到某一大段两侧:\(f_{i,j,k}\to f_{i+1,j,k+r_i}\)
  • 将两大段连接起来:\(f_{i,j,k}\to f_{i+1,j-1,k+2*r_i-1}\)

最后连成一段就是结果了:\(f_{n,1,k}\)

即:\(ans=\sum_k C^{n}_{l-k+n}×f_{n,1,k}\)

OK了!!!!

代码:

点击查看代码
#include <bits/stdc++.h>
#define dbg(x) cout << #x << '=' << x << endl
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define frep(i, r, l) for (int i = (r); i >= (l); i--)
#define int long long
using namespace std;
const int mod = 1e9 + 7;

const int N = 51;
const int M = 20010;

int n, l;
int a[N];
int f[N][N][M]; 
// 很好的数数题

// 前i个磁铁分成j段占用为k
// 1.单开一段 
// 2. 插到任意一段两侧
// 3. 插到两段中间将他们合并 
// ans = sum(C(l-k+n,n)*f[n][1][k]);

// Math
int fac[M], inf[M];

int Qpow(int a, int b) {
    int res = 1;
    while (b) {
        if (b & 1) res = res * a % mod;
        a = a * a % mod; b >>= 1;
    }
    return res;
}

int Inv(int a) {return Qpow(a, mod - 2);}

void Init(int n) {
    fac[0] = inf[0] = 1;
    rep(i, 1, n) fac[i] = fac[i - 1] * i % mod;
    rep(i, 1, n) inf[i] = Inv(fac[i]);
}

int C(int n, int m) {
    return fac[n] * inf[m] % mod * inf[n - m] % mod;
}

// Math

void work()
{
    cin >> n >> l;
    rep(i, 1, n) cin >> a[i];
    sort(a + 1, a + n + 1);
    Init(2 * l);
    f[0][0][0] = 1;
    rep(i, 0, n - 1) {
        rep(j, 0, i) {
            rep(k, 0, l - 1) {
                f[i + 1][j + 1][k + 1] = (f[i + 1][j + 1][k + 1] + f[i][j][k] * (j + 1) % mod) % mod;
                if (k + a[i + 1] <= l) 
                    f[i + 1][j][k + a[i + 1]] = (f[i + 1][j][k + a[i + 1]] + f[i][j][k] * j * 2 % mod) % mod;
                if (j >= 2 && k + a[i + 1] * 2 - 1 <= l) 
                    f[i + 1][j - 1][k + a[i + 1] * 2 - 1] = (f[i + 1][j - 1][k + a[i + 1] * 2 - 1] + f[i][j][k] * (j - 1) % mod) % mod;
            }
        }
    }
    int ans = 0;
    for (int k = 0; k <= l; k++)
        ans = (ans + C(l - k + n, n) * f[n][1][k] % mod) % mod;
    cout << ans << "\n";
}

signed main()
{
    // freopen("magnet.in", "r", stdin);
    // freopen("magnet.out", "w", stdout);
    std::ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int T = 1, opinput = 0;
    if (opinput) cin >> T;
    while (T--) work();
    return 0;
}
posted @ 2025-10-02 07:08  zhangxiao666  阅读(6)  评论(0)    收藏  举报