2024.11.15 CW 模拟赛
T1
诈骗题, 考虑贪心.
容易发现一个合法的方阵每一行或者每一列一定形如 "ABAB..." 或者 "BABA...".
那么可以对横行和纵列分别进行贪心.
最后取 \(\max\) 即可.
时间复杂度 \(\mathcal{O}(n^2)\).
#include "iostream"
using namespace std;
template <typename T>
inline void read(T &x)
{
x = 0;
char ch = getchar();
while (!isdigit(ch))
ch = getchar();
while (isdigit(ch))
x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
return;
}
const int N = 1e3 + 1;
short n, a[N][N];
int ans1 = 0, ans2 = 0;
inline void init()
{
read(n);
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= n; ++j)
read(a[i][j]);
int tmp1 = 0, tmp2 = 0;
for (int j = 1; j <= n; j += 2)
tmp1 += a[i][j];
for (int j = 2; j <= n; j += 2)
tmp2 += a[i][j];
ans1 += max(tmp1, tmp2);
}
return;
}
inline void calculate()
{
for (int j = 1; j <= n; ++j)
{
int tmp1 = 0, tmp2 = 0;
for (int i = 1; i <= n; i += 2)
tmp1 += a[i][j];
for (int i = 2; i <= n; i += 2)
tmp2 += a[i][j];
ans2 += max(tmp1, tmp2);
}
cout << max(ans1, ans2) << '\n';
return;
}
inline void solve()
{
init();
calculate();
return;
}
int main()
{
solve();
return 0;
}
T2
动态规划.
首先可以跑一遍 \(Floyd\) 计算最短路, 即用按键 \(j\) 替代按键 \(i\) 的最小天数.
接下来定义状态.
令 \(f_i\) 为到前 \(i\) 位是合法序列的最小花费.
那么有转移方程:
其中 \(cost[j,i,l]\) 表示将 \(j\) 到 \(i\) 全部变成按键 \(l\) 的花费.
这个可以使用前缀和进行优化.
届时时间复杂度为 \(\mathcal{O}(n^2 m^2)\), 不足以通过此题.
可以发现瓶颈是在枚举 \(f_j+cost[j,i,l]\).
因其具有单调性, 我们记 \(pre_c=dp_{i-k}-sum_{i-k,j},\ 1 \le c \le m\)
所以方程可以优化为:
时间复杂度 \(\mathcal{O}(nm)\).
#include "iostream"
#include "cstring"
using namespace std;
const int M = 27, N = 1e5 + 10;
int n, m, k;
int f[M][M];
int pos[N];
long long sum[N][M];
string s;
inline void init()
{
cin >> n >> m >> k;
cin >> s, s = " " + s;
for (int i = 1; i <= m; ++i)
for (int j = 1; j <= m; ++j)
cin >> f[i][j];
for (int K = 1; K <= m; ++K)
for (int i = 1; i <= m; ++i)
for (int j = 1; j <= m; ++j)
f[i][j] = min(f[i][K] + f[K][j], f[i][j]);
for (int i = 1; i <= n; ++i)
{
pos[i] = s[i] - 'a' + 1;
for (int j = 1; j <= m; ++j)
sum[i][j] = sum[i - 1][j] + f[pos[i]][j];
}
return;
}
long long dp[N], pre[N];
inline void calculate()
{
memset(dp, 63, sizeof dp);
dp[0] = 0;
memset(pre, 63, sizeof pre);
for (int i = 1; i <= n; ++i)
{
for (int j = 1; j <= m; ++j)
{
if (i >= k)
pre[j] = min(pre[j], dp[i - k] - sum[i - k][j]);
dp[i] = min(dp[i], pre[j] + sum[i][j]);
}
}
cout << dp[n] << '\n';
return;
}
inline void solve()
{
init();
calculate();
return;
}
int main()
{
cin.tie(nullptr)->ios::sync_with_stdio(false);
solve();
return 0;
}
T3
动态规划, 质因数分解
阅读题面, 容易发现原题意可以转化成:
当前有 \(cnt\) 个环, 且 \(\sum_{i=1}^{cnt} len_i=n\), 求 \(\sum \rm{lcm} (len_i)\).
而对于每一种情况, \(\rm{lcm}(len_i)\) 的值只与每个环长度的质因数有关, 是每一个质因数取最高次幂乘起来.
所以我们可以考虑枚举素数进行 dp.
设 \(f_{i,j}\) 表示当前所有长度不为 \(1\) 的环总长度为 \(i\), 每个环长度中最大的质因子不超过 \(p_j\) 的答案.
考虑枚举 \(p_j\) 的次幂作为新的环的长度(因为如果加到原来的环之后算答案回去重所以是一样的),
故有以下转移方程:
可以 \(\mathcal{O}(n^2)\) 枚举.
注意 \(i\) 需要倒序枚举(背包).
另外附一个结论:
如果 \(p\) 是一个素数集(包括 1), \(c\) 是一个自然数集, \(\lvert c \rvert = \lvert p \rvert = m\), 那么
这一类的拆分, 囊括了所有的答案.
- \(Proof\)
假设存在一种划分的 \(len_j\) 不符合上述条件, 记 \(len_j\) 有 \(k\) 个质因数.
那么可以把 \(len_j\) 拆成 \(k\) 个符合上述条件的环, 对 \(\rm{lcm}\) 没有影响.
并且可以证明拆出来的 \(k\) 个环的总长度不大于 \(len_j\) (类比 \(a,b \ge 2 \rightarrow ab \ge a+b\)).
#include "iostream"
#include "bitset"
using namespace std;
const int N = 1e4 + 1, M = 4e3 + 1;
short cnt = 0, p[M];
bitset<N> vis;
inline void calc_prime(int n)
{
for (short i = 2; i <= n; ++i)
{
if (!vis[i])
p[++cnt] = i;
for (short j = 1; i * p[j] <= n; ++j)
{
vis[i * p[j]] = 1;
if (!(i % p[j]))
break;
}
}
return;
}
short n;
int mod;
inline void init()
{
cin >> n >> mod;
calc_prime(n);
return;
}
int f[N];
inline void calculate()
{
f[0] = 1;
for (int i = 1; i <= cnt; ++i)
for (int j = n; j >= 1; --j)
for (int k = p[i]; k <= j; k *= p[i])
f[j] = (f[j] + 1ll * f[j - k] * k % mod) % mod;
int ans = 0;
for (int i = 1; i <= n; ++i)
ans = (ans + f[i]) % mod;
cout << ans + 1 << '\n';
return;
}
inline void solve()
{
init();
calculate();
return;
}
int main()
{
solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现