2025年4月代码部落月赛分析

前情提要:博主写快读快写魔怔了,所以代码里有快读快写函数,仅供参考(不过我用这个拿了许多时间最优解)

目录

前情提要:博主写快读快写魔怔了,所以代码里有快读快写函数,仅供参考(不过我用这个拿了许多时间最优解)

T1 求因数个数

T2 二维魔方

T3 修复网络

T4 黑白的电缆建设


T1 求因数个数

题目描述 (Description)

给出一个数字n,计算数字n的因数个数(包含1和n),

输入格式(Format Input)

输入一个数字n(1<=n<=1e18)

输出格式(Format Output)

输出n的因数个数

没什么好说的,分解质因数模版题,考虑分解质因数

a={p_1}^{b_1}\times{p_2}^{b_2}\times\ldots\times{p_n}^{b_n}

每个a的的因数w都应是 

w={p_1}^{c_1}\times {p_2}^{c_2}\times\ldots\times{p_n}^{c_n}(0\leq{c_i}\leq{b_i})

根据乘法定理,所有a的因数个数为

(b_1+1)\times(b_2+1)\times\ldots\times(b_n+1)

(本题直接枚举从1到\sqrt{n} 会T)

#include <bits/stdc++.h>
using namespace std;
inline long long rd()
{
	register long long x = 0; register bool f = false; register char c;
a:  c = getc(stdin), f |= c == '-'; if (c < '0' || c > '9') goto a;
b:  x = (x << 1) + (x << 3) + (c & 0xf), c = getc(stdin); if (c >= '0' && c <= '9') goto b;
	return f ? -x : x;
}
inline void prt(register long long x)
{
	register int stk[20], tp = 0;
a:  stk[tp++] = x % 10, x /= 10; if (x) goto a;
b:  putc(stk[--tp] | '0', stdout); if (tp) goto b;
}
inline void pt(register long long x)
{
	if (x < 0) putc('-', stdout), prt(-x);
	else prt(x);
}
int main()
{
	long long n = rd(), cnt, ans = 1;
	for (unsigned int i = 2; i * i <= n; i++)
	{
		cnt = 1;
		while (!(n % i)) n /= i, cnt++;
		ans *= cnt;
	}
	if (n != 1) pt(ans << 1);
	else pt(ans);
	return 0;
}

T2 二维魔方

题目描述 (Description)

林老师正在尝试发明一种新的二维魔方。现在给你一个n×n的二维魔方,例如一个3×3的魔方形如下图

众所周知魔方都可以进行旋转,所以也支持你对这个二维魔方做旋转,我们定义它可以进行下面的四种旋转任意次

  1. 将所有的行循环上移,行号为1的上移一行后行号为n,其余行号都视为减1
  2. 将所有的行循环下移,行号为n的下移一行后行号为1,其余行号都视为加1
  3. 将所有的列循环左移,列号为1的左移一行后列号为n,其余列号都视为减1
  4. 将所有的列循环右移,列号为n的右移一行后列号为1,其余列号都视为加1

例如将刚才的矩阵,应用一次操作3后,将形如下图

又众所周知,魔方又存在一个还原状态,所以我们定义我们的二维魔方的还原状态为变成了一个左对角线上都为1,其余部分都为0的矩阵,形如下图

又又众所周知,可能存在上面四种操作,无法还原魔方的情况,所以我们再加入一种操作

翻转:即将某个位置从1变成0,0变成1

但是要注意,每翻转一次这个魔方,都需要消耗1个单位的电力,但是旋转不需要消耗电力。翻转操作只能在执行完所有的旋转操作以后进行

又又又众所周知,林老师只会发明,不会求解,所以现在给定你一个魔方,求魔方变成还原状态所消耗的最少电量

输入格式(Format Input)

每组数据先输入一个整数 n(1≤n≤2000)。
接下来是一个n*n的矩阵,且仅由 0 和 1 组成。
保证所有测试用例中 n² 的值之和不超过 4×10⁶ 。

输出格式(Format Output)

每组数据输出一个整数,即变成 还原状态的最少电量

关于这题的小插曲:大家普遍过了t1t3,没人在了t2,老师说有三个人思路是对的,只是内存给的太极限了,就改大了一些,但事实上他们开的是二维数组,我只开了个一维数组就过了qwq

大致思考过程:首先要想到这个类似循环挪移的操作就开4*矩阵,化为枚举,但O(n^4)肯定过不去,考虑优化

1.这个很容易注意到吧,向下再向右移对答案没有任何影响,即我们在枚举第二维矩阵初始点没有意义(就是枚举的时候只要枚举最上面的一排就行了)

2.题意即统计斜对角线上0的个数与其余位置1的个数,显然统计斜对角线上个数只要O(n)的时间复杂度,又因为矩阵里面1的个数永远不变,因此只要统计总共1个个数再减斜对角线上1的个数就行了

3.至此时间复杂度已经优化成O(n^2),但是2*n^2的bool数组也开不下,先优化常数,这个很简单,我们是复制的矩阵,所以[i][j]的位置就是[i%n][j%n]的位置

4.很容易发现,矩阵在%n意义下有n条对角线,而一条正常对角线性质是i-j的值不会变,于是定义count数组,count[(i-j+n)%n]表示这条对角线上1的个数,这样空间也优化了

 

#include <bits/stdc++.h>
#define N 2010
using namespace std;
inline bool rd()
{
    register char c;
a:  c = getc(stdin); if (c < '0' || c > '1') goto a;
    return c == '1';
}
int n;
int ct[N];
int ttl;
int ans;
int main()
{
    cin >> n;
    static bool x;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            x = rd(), x ? (ct[(i - j + n) % n]++, ttl++) : 1;
    for (int i = 0; i < n; i++) ans = max(ans, ct[i]);
    printf("%d\n", n + ttl - (ans << 1));//由n-ans+ttl-ans化简而来
    return 0;
}

T3 修复网络

题目描述 (Description)

许老师正在致力于解决网络波动问题。现在有n台交换机通过m条网线相互连接,许老师打算在不改变交换机和网线布局的情况下,把所有的网线都换成新买的,每一条网线都连接着两台交换机,当任意两台交换机直接都可以通过网线直接或间接的相连时,我们认为许老师完成了网络的“基础布置”

每一条网线因为各种原因,更换起来的时间也不尽相同,为了尽快的完成任务,许老师直接发动了m位老师来帮他接网线,每个老师负责一条网线的布置。

但是月赛已经迫在眉睫了,同学们急需一个基本的网络来进行练习和比赛,许老师想知道最快在多少时间之后,他能完成他的“基础布置”

输入格式(Format Input)

第一行两个正整数 n,m 表示有n台交换机和m条网线
接下来m行 每行3个正整数x,y,t 表示编号为x和y的交换机之间有一条需要耗时t更换的网线

输出格式(Format Output)

输出最早在多少时间之后许老师能完成他的基础布置
如果全部的网线更换完都没有完成,输出-1

这道题就更不必细说了,没学过最小生成树都能按题意写个kruskal

#include <bits/stdc++.h>
using namespace std;
inline int rd()
{
	register int x = 0; register bool f = false; register char c;
a:  c = getc(stdin), f |= c == '-'; if (c < '0' || c > '9') goto a;
b:  x = (x << 1) + (x << 3) + (c & 0xf), c = getc(stdin); if (c >= '0' && c <= '9') goto b;
	return f ? -x : x;
}
inline void prt(register int x)
{
	register int stk[20], tp = 0;
a:  stk[tp++] = x % 10, x /= 10; if (x) goto a;
b:  putc(stk[--tp] | '0', stdout); if (tp) goto b;
}
inline void pt(register int x)
{
	if (x < 0) putc('-', stdout), prt(-x);
	else prt(x);
}
struct Edge
{
	int u, v, w;
}E[100010];
int f[1010];
int ff(int x) { return (f[x] == x) ? x : (f[x] = ff(f[x])); }
int n, m;
int ans = 0;
int main()
{
	n = rd(), m = rd();
	for (register unsigned int i = 0; i < m; i++) E[i] = { rd(),rd(),rd() };
	sort(E, E + m, [](Edge x, Edge y)->bool {return x.w < y.w; });
	for (register unsigned int i = 1; i <= n; i++) f[i] = i;
	for (register unsigned int i = 0; i < m; i++)
	{
		if (ff(E[i].u) == ff(E[i].v)) continue;
		f[ff(E[i].u)] = ff(E[i].v);
		ans = max(ans, E[i].w);
	}
	register int af = ff(1);
	for (register unsigned int i = 2; i <= n; i++) if (ff(i) != af) { puts("-1"); return 0; }
	pt(ans);
	return 0;
}

T4 黑白的电缆建设

题目描述 (Description)

Shiro 与 Kuro 住在一个奇妙的城市里。

这个城市可以看作是一张 N 行 M 列的网格图,左上角网格点坐标为 (0,0),右下角网格点坐标为 (N,M),网格点之间存在一些电缆。一开始,所有电缆都是没有启用的(也就是说每条电缆中间都是断开的)。

具体的,对于网格图中的任意一个整数坐标点 (x,y):

  • 只要 y+1≤N,那么坐标 (x,y) 与 (x+1,y) 的两个网格点之间存在一条电缆。
  • 只要 y+1≤M,那么坐标 (x,y) 与 (x,y+1) 的两个网格点之间存在一条电缆。
  • 只要 x+1≤N 并且 y+1≤M,那么坐标 (x,y) 与 (x+1,y+1) 的两个网格点之间存在一条电缆。

例如,当 N=3,M=4 时,这个城市的电缆连接情况如下图所示。

P1

这座城市的左上角与右下角(即坐标 (0,0) 与 (N,M) 处)存在两座发电厂,发电厂所产生的电可以通过电缆传给城市中的每个用电位置。因此,我们需要选择去启用一些电缆,以便将电从两座发电厂传递出去。

地图中的每条电缆在启用后都能够获得一定的经济效益。我们的目的自然就是让能够获得的经济效益总和最大。

但不幸的是,如果我们错误地启用电缆,导致两座发电厂通过某些电缆连接到了一起,那么可能会导致短路而造成全城停电!所以在启用电缆的时候请务必注意这一点!

现在将每条电缆启用后能获得的经济效益告诉你,请你帮忙求出,在不让两座发电厂连接到一起的前提下,能够获得的最大经济效益总和是多少?

输入格式(Format Input)

第一行包含两个正整数 N,M,表示网格图的行数与列数。

接下来 N+1 行,第 i 行包含 M 个正整数 Ai,1​,Ai,2​,⋯,Ai,M​,依次代表图中每条横着的电缆在启用后所能够获得的经济效益,其中 Ai,j​ 表示连接 (i−1,j−1) 与 (i−1,j) 两个网格点的电缆。

接下来 N 行,第 i 行包含 M+1 个正整数 Bi,1​,Bi,2​,⋯,Bi,M+1​ ,依次代表图中每条竖着的电缆在启用后所能够获得的经济效益,其中 Bi,j​ 表示连接 (i−1,j−1) 与 (i,j−1) 两个网格点的电缆。

接下来 N 行,第 i 行包含 M 个正整数 Ci,1​,Ci,2​,⋯,Ci,M​,依次代表图中每条斜着的电缆在启用后所能够获得的经济效益,其中 Ci,j​ 表示连接 (i−1,j−1) 与 (i,j) 两个网格点的电缆。

  • 1≤N,M≤500
  • 1≤Ai,j​,Bi,j​,Ci,j​≤10000
  • 保证答案在 32 位整型 int 的范围内

具体数形对应关系可参考下图:

P2


 

P3

P4

输出格式(Format Output)

一个整数,表示在不让两座发电厂连接到一起的前提下,能够获得的最大经济效益总和。

emm这题一眼最小割(不会的滚去削网络流),但是这道题是一个看上去很有规律的题,是巨难的优化建模,所以博主敲了个Dinic55tps后因T跑路了,有同学说这可能是一个单峰函数要三分,但看上去不是(我不信提高组难度能给我上一个模拟退火) ,于是连HLPP都懒得敲就跑路了

只有55分就不放代码了

os:也是爽了一把

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值