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;
}
本文来自博客园,作者:zhangxiao666,转载请注明原文链接:https://www.cnblogs.com/zhangxiao666qwq/p/19123152