补题报告4

news/2024/12/22 0:57:28/文章来源:https://www.cnblogs.com/Picecone-zzs/p/18446760

背景

CSP-J模拟赛
考得最好的一次


得分

\(T1\): \(AC\)
\(T2\): \(AC\)
\(T3\): \(0\)
\(T4\): \(20\)


\(T1\) 三个 (\(Three\))

赛时\(AC\)

概述

\(A,B,C\)三种微生物,他们会繁殖,在每分钟:
每个 \(A\) 可繁殖出一个\(A\),一个\(B\),一个\(C\)
每个 \(B\) 可繁殖出两个\(A\),两个\(C\)
每个 \(C\) 可繁殖出一个\(A\),一个\(B\)
注:三种繁殖同时进行
每种微生物现各有1个,求\(n\)秒后,\(A\)\(B\)\(C\) 三种微生物数量的奇偶

思路

奇偶?正常来讲,应输出数量,输出奇偶可能是有规律可循
先打个小表:

输出
i    a b c
1  : 5 3 4
2  : 20 12 15
3  : 79 47 59
4  : 311 185 232
5  : 1224 728 913
6  : 4817 2865 3593 
7  : 18957 11275 14140
8  : 74604 44372 55647
9  : 293599 174623 218995
10 : 1155439 687217 861840
11 : 4547152 2704496 3391713
12 : 17895009 10643361 13347857
13 : 70424597 41886227 52529588
14 : 277151236 164840412 206726639
15 : 1090709935 648718287 813558699

哇!有规律(狂喜
观察可得:
\(i=2,5,8,11,14……\)时,\(A\)为偶数,否则为奇数
\(i=2,5,8,11,14……\)时,\(B\)为偶数,否则为奇数
\(i=1,4,7,10,13……\)时,\(C\)为偶数,否则为奇数

所以 若$$

\(O(1)\)做法出炉:

代码

Code
#include <cstdio>
using namespace std;
int n;
int main(){scanf("%d",&n);if(n % 3 == 2)  printf("even\neven\n");elseprintf("odd\nodd\n");if(n % 3 == 1) printf("even");elseprintf("odd");return 0;
} 

\(T2\) 合体(\(fit\)

赛时\(AC\)!!!!!!!!!!!!!!!!!!

概述

有一些整数:\(a_1\) ~ \(a_n\) ,它们范围在1~ \(m\)
你有魔法,可将2个一样的合成,变成1个原数+1
例:\(2,2\) \(\implies\) \(3\)
现有\(q\)次询问,每次给定一个\(x\),问施完魔法后(可无限次使用太强了),最多能得到几个\(x\)

思路

  1. 输入,用桶存储各数个数
  2. 输入\(x\)
  3. 合成
  4. 输出

Emmm……,一开始,我代码执行的顺序是 \(1 \to 3 \to 2 \to 4\)
做完,又想后输入\(x\),结果合成的数很大,而\(x\)不需要那么大,不就浪费了时间?
纯属想多了
所以,我又改进了代码,运行顺序就变成了\(1 \to 2 \to 3 \to 4\)
还有还有,昨天老师说,数据过大要用 \(scanf\)\(printf\) ,记着了,今天全用的它俩,今天这题不用 \(TLE\) \(70\) 分,用了\(AC\)

代码

最正确的一集

Code
#include <cstdio>
using namespace std;
const int maxn = 1e6+1111;
bool flag=1;
int n,m,q;
int maxx;//要求输出的数的最大值
int a[maxn];
//cnt[]存转换前个数
int cnt[maxn];//n,m最大都是1e6,maxn=maxm
int x[maxn];
int main() {scanf("%d%d",&n,&m);for(int i=1; i<=n; ++i) {scanf("%d",&a[i]);++cnt[a[i]];}scanf("%d",&q);for(int i=1; i<=q; ++i) {scanf("%d",&x[i]);maxx = max(maxx,x[i]);} //转换for(int i=2; i<=maxx; ++i) cnt[i] += cnt[i-1]/2;for(int i=1;i<=q;++i){printf("%d",cnt[x[i]]);if(q) printf("\n");}return 0;
}

\(T3\) 矩阵(\(matrix\)

赛时全 WA (

概述

给定一个矩阵,定义一个矩阵的快乐值为该矩阵中所有数字的异或和,求该矩阵的所有子矩阵的快乐值之和是多少?

赛时思路

四重循环,枚举该矩阵的左上顶点与右下顶点
写完了
写 炸 了

难评
#include <cstdio>
using namespace std;
const int maxn = 310;
int n,m;
int a[maxn][maxn];
long long sum[maxn][maxn];
long long ans;
int main() {scanf("%d%d",&n,&m);for(int i=1; i<=n; ++i) {for(int j=1; j<=m; ++j) {scanf("%d",&a[i][j]);sum[i][j] = a[i][j];if(i!=1) sum[i][j] ^= sum[i-1][j];if(j!=1) sum[i][j] ^= sum[i][j-1];if(i!=1&&j!=1) sum[i][j] ^= sum[i-1][j-1];}}sum[1][1] = 0;for(int a=1; a<=n; ++a) {for(int b=1; b<=m; ++b) {for(int c=a+1; c<=n; ++c) {for(int d=b+1; d<=m; ++d) {long long h = sum[c][d];if(b != 1) h ^= sum[c][b-1];if(a != 1) h ^= sum[a-1][d];if(a != 1 && b != 1) h ^= sum[a-1][b-1];ans += h;}}}}printf("%lld",ans);return 0;}

歪解(bushi

考虑将二维数组压成一维的;
枚举起始行 i 和终止行 j ,这个范围内的每一列都求异或值 x[k] ;即 x[k] 为 a[i][k] ~ a[j][k] 的异或值。
之后再对于x数组,求前缀异或值,然后枚举其左右端点,计算区间异或值即可。
时间复杂度\(O(n^4)\),能拿个20分(原因在于最后统计)

20分
#include <iostream>
#include <cstring>
#define ll long long
using namespace std;
const int maxn=305;
int n, m, a[maxn][maxn], x[maxn], xo[maxn];
int main() {cin >> n >> m;for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)cin >> a[i][j];ll ans = 0;for (int i = 1; i <= n; i++) {//枚举起始行memset(x, 0,sizeof(x));for (int j = i; j <= n; j++) {//枚举终止行for (int k = 1; k <= m; k++) {x[k] ^= a[j][k];// i到j行压成一行xo[k] = xo[k - 1] ^ x[k]; //求前缀异或值}for (int l = 1; l <= m; l++)for (int r = l; r <= m; r++) //枚举区间ans += (xo[r] ^ xo[l - 1]); //计算区间异或}}cout << ans << endl;return 0;
}

优化

对于上述代码,枚举完起始行和终止行之后,还需要\(O(m^2)\)去计算结果,这一部分可以考虑优化。

可以按位去考虑,对于某个区间,按位异或之后的值,的某一位,是否为1。只需要考虑这个区间内的这一位的1的个数是奇数个还是偶数个。

也可以考虑\(xo\)数组 ans += (xo[r] ^ xo[l - 1]); ,按位考虑,某一位如果想被累计到答案里,那么\(xo[r]\)的这一位和\(xo[l-1]的这一位\)不相同。

所以可以考虑把\(xo\)拆位,如果当前这一位是\(1\),那么就考虑它前面这一位是\(0\)的情况有多少个,反之同理。

正确的
int n, m, a[N][N], x[N], xo[N];
int main() {freopen("matrix.in", "r", stdin);freopen("matrix.out", "w", stdout);cin >> n >> m;for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++)cin >> a[i][j];ll ans = 0;for (int i = 1; i <= n; i++) {//枚举起始行mem(x, 0);for (int j = i; j <= n; j++) {//枚举终止行for (int k = 1; k <= m; k++) {x[k] ^= a[j][k];xo[k] = xo[k - 1] ^ x[k];}//求前缀异或值for (int p = 0; p < 10; p++) {//按位枚举int cnt0 = 1; //记录第p位为0的个数int cnt1 = 0; //记录第p位为1的个数for (int k = 1; k <= m; k++) {if (xo[k] & (1 << p)) {//如果当前数字,第p位是1,那么要考虑前面有多少0ans += 1ll * (1 << p) * cnt0;cnt1++;} else {//如果当前数字,第p位是0,那么要考虑前面有多少1ans += 1ll * (1 << p) * cnt1;cnt0++;}}}}}cout << ans << endl;return 0;
}

\(T4\) 数对(\(pair\))

赛时20

概述

\(a_1,……a_n\)
\(b_1,……b_m\)
再给一正整数\(p\),要求生成\(c_1,……,c_{m \times n }\)
且满足$c_{i-1 \times m + j} = (a_i + b_j) $ \(mod\) \(p\)
\(c\)中逆序对

思路

暴力求解
喜得20

暴力
#include <cstdio>
using namespace std;
const int maxn = 1e3+1111;
int a[maxn];
int b[maxn];
long long c[maxn*maxn];
int n,m,p;
long long cnt;
int main(){scanf("%d%d%d",&n,&m,&p);for(int i=1;i<=n;++i)scanf("%d",&a[i]);for(int i=1;i<=m;++i)scanf("%d",&b[i]);for(int i=1;i<=n;++i){for(int j=1;j<=m;++j){c[(i-1) * m + j] = (a[i] + b[j]) % p;}}for(int i=1;i<=n*m;++i){for(int j=i+1;j<=n*m;++j){if(c[i] > c[j]) ++cnt;}}printf("%lld",cnt);return 0;
}

正解

可将\(c\)数组拆成\(n\),每块有\(m\)
再用逆序对在块内求,块间求

  1. 对于块内
    观察到值域非常小,我们可以对 \(b\) 数组记录数字出现次数 \(num\)
    枚举到当前数字 \(x\) ,计算逆序数时,可以枚举比 \(x\) 大的数字的出现次数即可。
    也就是记录 \(num[b[i]+1]~num[p-1]\) 的和。
    考虑 \(b\) 后续需要变化 \((+a[j])\) 。所有我们记录一个数组 \(nixu[k]\)
    表示为对于 \(b\) 数组所有数组都加 \(k\) 之后,逆序数为多少。
  2. 对于块与块
    我们可以记录之前所有数字的出现次数,当前块一定是在之前块的后面
    所以直接枚举值域,统计逆序数即可。
30分long long
int n, m, p, a[M], b[M];
ll num[10], numb[10], nixu[10]; // nixu[i]表示b数组+i之后的逆序数。
int main() {freopen("pair.in", "r", stdin);freopen("pair.out", "w", stdout);CLOSEcin >> n >> m >> p;for (int i = 1; i <= n; i++)cin >> a[i];for (int i = 1; i <= m; i++) {cin >> b[i];numb[b[i]]++;}for (int j = 0; j < p; j++) {mem(num, 0);for (int i = 1; i <= m; i++) {for (int k = b[i] + 1; k < p; k++)nixu[j] += num[k];num[b[i]]++;b[i] = (b[i] + 1) % p;}}mem(num, 0);ll ans = 0;for (int i = 1; i <= n; i++) {ans += nixu[a[i]];for (int j = 0; j < p; j++) {int x = (j + a[i]) % p;for (int k = x + 1; k < p; k++)ans += 1ll * numb[j] * num[k];}for (int j = 0; j < p; j++)num[(j + a[i]) % p] += numb[j];}cout << ans << endl;return 0;
}

优化后的

参考代码(仅供参考)
int n, m, p, a[M], b[M];
ll num[10], numb[10], nixu[10]; // nixu[i]表示b数组+i之后的逆序数。ll ans[200], cnt = 0;void jia(ll k)
{ans[0] += k;int pos = 0;while (true) {if (ans[pos] >= 1000000) {ans[pos + 1] += ans[pos] / 1000000;ans[pos] %= 1000000;if (++pos > cnt)cnt++;} elsebreak;}
}
int main() {cin >> n >> m >> p;for (int i = 1; i <= n; i++)cin >> a[i];for (int i = 1; i <= m; i++) {cin >> b[i];numb[b[i]]++;}for (int j = 0; j < p; j++) {mem(num, 0);for (int i = 1; i <= m; i++) {for (int k = b[i] + 1; k < p; k++)nixu[j] += num[k];num[b[i]]++;b[i] = (b[i] + 1) % p;}}mem(num, 0);for (int i = 1; i <= n; i++) {// ans += nixu[a[i]];jia(nixu[a[i]]);//优化32行加法 for (int j = 0; j < p; j++) {int x = (j + a[i]) % p;for (int k = x + 1; k < p; k++)jia(1ll * numb[j] * num[k]);//优化38行加法 // ans += 1ll * numb[j] * num[k];}for (int j = 0; j < p; j++)num[(j + a[i]) % p] += numb[j];}cout<<ans[cnt];//最前面一定不用补0,单独输出 for (int i = cnt-1; i >= 0; i--)printf("%06lld",ans[i]);//有可能要补0 // cout << ans[i];return 0;
}

官方题解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/808010.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

9-贪心算法

参考:代码随想录 题目分类大纲如下:贪心算法理论基础 什么是贪心? 贪心的本质是选择每一阶段的局部最优,从而达到全局最优。 贪心的套路(什么时候用贪心) 贪心算法并没有固定的套路,说白了就是常识性推导加上举反例。靠自己手动模拟,如果模拟可行,就可以试一试贪心策略…

【VMware VCF】使用 SoS 实用程序检查 VCF 环境的运行状态以及收集组件的日志信息。

VMware Cloud Foundation 解决方案中有一个叫 Supportability and Serviceability(SoS)可支持性和可维护性的实用程序,可能你在初始构建 VCF 管理域的时候使用过这个工具,当时使用这个工具在 VMware Cloud Builder 虚拟机中将用于部署的 VCF 管理域的 Excel 参数表转换为 J…

PbootCMS数据库配置,修改为Mysql数据库,配置Mysql出错解决办法

如果你在将PbootCMS从SQLite切换到MySQL时遇到了连接问题,可以按照以下步骤进行排查和解决: 步骤 1: 修改数据库连接驱动类型 确保你正确地修改了数据库连接驱动类型。PbootCMS支持多种数据库驱动,你可以逐一尝试不同的驱动类型。 步骤 2: 修改数据库服务器地址 将数据库服务…

pbootcms模板后台编辑器无法上传图片提示:后端配置项没有正常加载,上传插件不能正常使用!

针对 PbootCMS 中 UEditor 编辑器单图片上传按钮无反应以及多图片上传提示“后台配置项返回格式出错,上传功能将不能正常使用!”的问题,可以按照以下步骤进行排查和修复。 1. 修改时区设置 首先,根据你提供的信息,时区设置可能存在问题。请按照以下步骤修改时区设置:打开…

第八届2024御网杯WP

WEBinput_data使用工具https://github.com/kost/dvcs-ripper./rip-svn.pl -u http://101.200.58.4:10005/.svn下载下来.svn目录然后查看结构发现几个文件cd进去目录,然后cat 文件名字即可看到 flag{5674938f-803d-4c41-8f84-a77f5164bb4f}Flag: flag{5674938f-803d-4c41-8f84…

给PbootCMS增加换行标签br=1

在 PbootCMS 中,如果你需要在前端显示一个包含换行符的简介字段,并且希望这些换行符能够正确显示为 HTML 中的换行,可以通过自定义解析器来实现这一功能。以下是详细的步骤: 步骤 1: 修改 ParserController.php 文件打开文件: 打开 \apps\home\controller\ParserControlle…

pbootcms如何显示按文章内容搜索,而不是搜索标题

在 PbootCMS 中,默认情况下搜索功能通常是基于文章标题进行的。如果你想让搜索功能基于文章内容进行,可以通过以下步骤实现: 步骤 1: 修改搜索表单 在搜索表单中添加一个隐藏字段 field,并将它的值设为 content。这样可以让系统知道搜索时应该针对文章内容进行匹配。 修改后…

PbootCMS文章列表序号怎么写?

根据你提供的信息,我们可以进一步了解如何使用 pboot:list 标签,并结合 [list:n]、[list:i] 和 [list:id] 进行一些实用的功能实现。下面是一些具体的示例和应用场景: 1. 显示列表序号 假设我们需要显示一个列表,并且希望序号从 0 开始:html{pboot:list num=10} <li>…

PbootCMS隐藏指定 scode 的菜单各种条件判断和标签

{pboot:nav} <li {pboot:if([nav:scode] == 2 || [nav:scode] == 4 || [nav:scode] == 6)}style="display: none;"{/pboot:if}><a href="[nav:link]">{nav:name}</a> </li> {/pboot:nav}扫码添加技术【解决问题】专注中小企业网站…

PbootCMS判断导航从第几个开始各种条件判断和标签

{pboot:nav} {pboot:if([nav:i] > 2)} <li><a href="[nav:link]">{nav:name}</a></li> {/pboot:if} {/pboot:nav}扫码添加技术【解决问题】专注中小企业网站建设、网站安全12年。熟悉各种CMS,精通PHP+MYSQL、HTML5、CSS3、Javascript等。…

PbootCMS导航栏 logo 居中判断各种条件判断和标签

{pboot:nav} <a href="[nav:link]">{nav:name}</a> {pboot:if([nav:i] == 3)} <img src="{pboot:sitelogo}" /> {/pboot:if} {/pboot:nav}扫码添加技术【解决问题】专注中小企业网站建设、网站安全12年。熟悉各种CMS,精通PHP+MYSQL、HT…

PbootCMS判断列表页有无内容,无内容返回提示各种条件判断和标签

{pboot:if({page:rows} > 0)} <div class="page"><a href="{page:index}">首页</a><a href="{page:pre}">上一页</a>{page:numbar}<a href="{page:next}">下一页</a><a href="{…