11月7日 NOIP模拟(难题math、矩阵游戏matrix、括号序列seq、道路road) - 模拟赛记录

news/2024/11/7 21:08:29/文章来源:https://www.cnblogs.com/jerrycyx/p/18533799

Preface

T1 试图找规律失败,正经推反而几分钟就出来了。以后应该少想这些歪门邪道(除非实在闲的蛋疼或者没有一点头绪,且必须要打完所有能打的子任务比如暴力或特殊性质;而且必须在用常规方法思考过后,才能够用一些稍微不那么常规的方法)

至于 T2、T3、T4,因为知道 T1 浪费了太多时间,都是直接打暴力 + 特殊性质拿所有部分分,最后才来挨个挨个想正解。事实证明,这种方法十分有效,没有浪费任何时间暴力(超级模拟类型的暴力除外)和特殊性质绝对不是浪费时间)。

赛时主攻 T4 去了,但是因为 SPJ 的错漏之处(把错误的路径直接 continue 掉),导致我误解了我的代码错误位置,最后没有调出来,所以以后还得多多靠自己,好好核对草稿的结果和实际输出的结果是否一致

难题(math

\(c_i\) 表示 \(f(j)=i, j \le n\)\(j\) 的个数,那么答案显然可以转化成 \(\sum i \times c_i\),问题在于怎么求 \(c_i\)

容易发现 \(f(x)=y\) 当且仅当 \(1 \mid x, 2 \mid x, \cdots, y-1 \mid x\)\(y \nmid x\),其中前一条条件可以转化成 \(\operatorname{lcm}(1,2,\dots,y-1) \mid x\)

运用容斥,满足条件一的数有 \(\left\lfloor \frac{n}{\operatorname{lcm}(1,2,\dots,y-1)} \right\rfloor\) 个,而同时满足条件一和条件二的数有 \(\left\lfloor \frac{n}{\operatorname{lcm}(\operatorname{lcm}(1,2,\dots,y-1),y)} \right\rfloor = \left\lfloor \frac{n}{\operatorname{lcm}(1,2,\dots,y)} \right\rfloor\) 个,所以:

\[c_i = \left\lfloor \frac{n}{\operatorname{lcm}(1,2,\dots,y-1)} \right\rfloor - \left\lfloor \frac{n}{\operatorname{lcm}(1,2,\dots,y)} \right\rfloor \]

\(y=50\) 的时候,\(\operatorname{lcm}(1,2,\dots,y)\) 就远超 \(10^{16}\) 了,所以可能的最大 \(f\) 值也不会超过 \(50\)(实际上大概在 \(41\) 左右)

然后就做出来了,如果预处理一下 \(\operatorname{lcm}(1,2,\dots,i)\) 还可以加点速。

核心代码:

int T=IO::read();
g[1]=1;
for(int i=2;g[i-1]<=N;i++)g[i]=lcm(g[i-1],i);
while(T--)
{long long n=IO::read<long long>();long long ans=0;for(int i=2;g[i-1]<=n;i++)ans=(ans+1ll*i*(n/g[i-1]-n/g[i]))%P;IO::write(ans%P); putchar('\n');
}
完整代码
#include<cstdio>
using namespace std;namespace IO{template<typename TYPE=int>
TYPE read()
{TYPE x=0; bool neg=false;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') neg=true;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^'0');ch=getchar();}return neg?-x:x;
}template<typename TYPE>
void write(TYPE x)
{if(!x){putchar('0');return;}if(x<0){putchar('-');x=-x;}static int sta[55];int statop=0;while(x){sta[++statop]=x%10;x/=10;}while(statop)putchar('0'+sta[statop--]);return;
}}const long long N=1e16;
const int P=1e9+7;long long gcd(long long x,long long y){return y?gcd(y,x%y):x;}
inline long long lcm(long long x,long long y){return x*y/gcd(x,y);}
long long g[1005];int main()
{freopen("math.in","r",stdin);freopen("math.out","w",stdout);int T=IO::read();g[1]=1;for(int i=2;g[i-1]<=N;i++)g[i]=lcm(g[i-1],i);while(T--){long long n=IO::read<long long>();long long ans=0;for(int i=2;g[i-1]<=n;i++)ans=(ans+1ll*i*(n/g[i-1]-n/g[i]))%P;IO::write(ans%P); putchar('\n');}return 0;
}

矩阵游戏(matrix

因为每次删行的时候每一列都会收到同等的影响,所以每一列的相对大小不改变,选择优先级也不改变;删列时每行同理。

所以,删行或者删列都不影响对方的决策,删行和删列的顺序也就不重要了。那么我们就直接求出只删行 \(i\) 次的最大得分 \(fr_i\)(代码中为 Row::f[i]) 和只删列 \(i\) 次时的最优得分 \(fc_i\)(代码中为 Column::f[i]),规定先删行后删列,那么删了 \(i\) 次行时的答案就是 \(fr_i \times fc_{k-i}\)但是,因为删列时的矩形实际上已经不是完整的矩形了,而是已经有 \(i\) 行被减过了(不一定不重复),所以所删的每一列都应当已经少了 \(i \times p\),总共少了 \(i \times (k-i) \times p\),最终的答案就是 \(\max\{ fr_i \times fc{k-i} - t \times (k-i) \times p\}, 0 \le i \le k\)

至于求只选行和直选列的具体过程,可以用优先队列维护行 / 列的总和,每次贪心地找最大总和来删,注意删完之后还要放回去。

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;namespace IO{template<typename T=int>
T read()
{T x=0; bool neg=false;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') neg=true;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^'0');ch=getchar();}return neg?-x:x;
}template<typename T>
void write(T x)
{if(!x){putchar('0');return;}if(x<0){putchar('-');x=-x;}static int sta[55];int statop=0;while(x){sta[++statop]=x%10;x/=10;}while(statop)putchar('0'+sta[statop--]);return;
}}const int N=1005,M=1005,K=1e6+5;
int n,m,k,p;
int a[N][M];namespace Row{long long f[K];priority_queue<long long> pq;void Solve(){for(int i=1;i<=n;i++){long long sum=0;for(int j=1;j<=m;j++)sum+=a[i][j];pq.push(sum);}for(int i=1;i<=k;i++){long long top=pq.top(); pq.pop();f[i]=f[i-1]+top; pq.push(top-1ll*m*p);}return;}}namespace Column{long long f[K];priority_queue<long long> pq;void Solve(){for(int i=1;i<=m;i++){long long sum=0;for(int j=1;j<=n;j++)sum+=a[j][i];pq.push(sum);}for(int i=1;i<=k;i++){long long top=pq.top(); pq.pop();f[i]=f[i-1]+top; pq.push(top-1ll*n*p);}return;}}void Solve()
{Row::Solve();Column::Solve();long long ans=-1e18; //注意初始化! for(int i=0;i<=k;i++)ans=max(ans,Row::f[i]+Column::f[k-i]-1ll*i*(k-i)*p); //有i*(k-i)个位置要被删两次IO::write(ans);return;
}int main()
{#ifndef JC_LOCALfreopen("matrix.in","r",stdin);freopen("matrix.out","w",stdout);#endifn=IO::read(),m=IO::read(),k=IO::read(),p=IO::read();for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)a[i][j]=IO::read();Solve();return 0;
}

括号序列(seq

个人感觉最难的一道题,题解写的做法和代码写法好像有点问题,不过能 AC 就很奇怪,我的写法中的更新方式感觉更好理解也更符合逻辑,同样能 AC。

image

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;const int N=25,LEN=4e5+5;
int n; char str[LEN];int sum[N],minsum[N],cnt[N][LEN];
int f[(1<<(N-5))+5],tot[(1<<(N-5))+5];
int main()
{freopen("seq.in","r",stdin);freopen("seq.out","w",stdout);scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%s",str+1);int len=(int)strlen(str+1);for(int j=1;j<=len;j++){sum[i]+=str[j]=='(' ? 1 : -1;minsum[i]=min(minsum[i],sum[i]);if(minsum[i]>=sum[i]) cnt[i][-sum[i]]++;}}for(int i=0;i<(1<<n);i++)f[i]=-0x3f3f3f3f;f[0]=0;int ans=0;for(int z=0;z<(1<<n);z++){for(int i=1;i<=n;i++)if(!((z>>(i-1))&1)){int nxt=z|(1<<(i-1));if(tot[z]+minsum[i]>=0){if(f[z]+cnt[i][tot[z]]>f[nxt]){f[nxt]=f[z]+cnt[i][tot[z]];tot[nxt]=tot[z]+sum[i];ans=max(ans,f[nxt]);}}else ans=max(ans,f[z]+cnt[i][tot[z]]);}ans=max(ans,f[z]);}printf("%d\n",ans);return 0;
}

路程(road

为方便叙述,题面中的 \(n\) 在这里用 \(q\) 表示,而这里的 \(n,m\) 则分别表示点数,边数,最后一个点均指 \(114\) 号点(这仰慕前辈……)

首先看 \(q=2^k\) 的特殊性质。

首先有 \(n=k+1\) 个点,从点 \(i\) 向点 \(i+1\) 连一条边,边长为 \(2^{k-i}\),这样可以凑出 \([0,2^k-1]\) 的所有路径,最后再从 \(1\) 向末端点连接一条边长为 \(2^k\) 的边,这样就可以凑出 \([0,2^k]\) 了。

然后再考虑普适情况。

如果不连最后一条边,而是从 \(1\)\(i\) 连一条长度为 \(2^k\) 的边,那么其和后面所有边组合,就可以瞬间多出 \(2^{n-i}\) 条路径,范围是 \([2^k,2^k+2^{n-i}-1]\)

再从 \(1\)\(j\) 连一条长度为 \(2^k+2^{n-i}\) 的边,那么就可以多出 \(2^{n-j}\) 条路径,范围是 \([2^k+2^{n-i},2^k+2^{n-i}+2^{n-j}-1]\)

重复上述过程,每次新连接的边权就是现在已有的最大路径长度加一,运用二进制分解可以将任意 \(q\) 转化成若干个上述形式的区间,然后像上面一样连接新边即可。

最大点数 \(\log_2 q +1\),最大边数 \(3 \log_2 q\),满足题意。

注意当 \(q=2^k-1\) 的时候可能出 BUG,可能需要特殊处理一下。

#include<cstdio>
using namespace std;const int N=105,M=105;
int q;
struct rAllan{int x,y,z;
}edge[M];
int m=0;
int vertex[N];int main()
{freopen("road.in","r",stdin);freopen("road.out","w",stdout);scanf("%d",&q);int lg2=0,tq=q;while(tq) lg2++,tq>>=1;int n=lg2;for(int i=1;i<n;i++)vertex[i]=i;vertex[n]=114;for(int i=1;i<n;i++){int x=i,y=vertex[i+1];int z=1<<(n-i-1);edge[++m]={x,y,z};edge[++m]={x,y,0};} //[0,2^lg2-1]int rest=q-((1<<(lg2-1))-1);int now=1<<(lg2-1);bool flag=false;for(int p=lg2;p>=0;p--){if(rest-(1<<p)>=0){if(n-p==1) flag=true;else{edge[++m]={1,vertex[n-p],now};rest-=(1<<p);now+=(1<<p);}}}if(flag) edge[++m]={1,114,q};printf("%d %d\n",n,m);for(int i=1;i<=m;i++)printf("%d %d %d\n",edge[i].x,edge[i].y,edge[i].z);return 0;
}

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

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

相关文章

ESP32学习笔记2(GPIO的数字输入输出功能)

1. 普通5mm直径LED参数测定实验 以上为普通5mm直径LED,手册建议持续工作电流为20mA以内。以下,采用学生电源(带控压限流功能)通过限流电阻170欧给各色LED供电,通过缓慢加压测流和观察LED亮度的方法,确定电流、压降与亮度关系,实测该批次LED颜色与压降大致如下: 颜色 …

2024/11/7日工作总结

学习JS基础知识: 1.事件绑定:点击查看代码 <!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>Title</title> </head> <body><img id="龙泡泡" src="../imgs/年…

实验三 c++

实验任务一 源代码 button.hpp1 #pragma once2 3 #include<iostream>4 #include<string>5 6 using std::string;7 using std::cout;8 9 class Button{ 10 public: 11 Button(const string &text); 12 string get_label()const; 13 void click(); 1…

学习openeuler操作系统的记录本

1.下载以及配置openeuler在官网里面下载openeuler操作系统,在官网的文档里面里面查看相对应的注意事项,(一定要会阅读官方文档),在官网查看下载的对应操作系统需要的最小cpu,以及磁盘大小等分配合适的虚拟硬盘,配置的过程要一步一步来,防止出现分配不合理,而导致的操作…

AWVS安装及破解

以kali为例安装AWVS复制安装文件到kali中 AWVS百度网盘下载 root用户打开kali并把安装包解压到/opt/AWVS路径中 7z x acunetix_23.11.231123131_x64.7z -o/opt/AWVS/编辑host文件 vim /etc/hosts将以下内容加在hosts文件尾部 127.0.0.1 erp.acunetix.com127.0.0.1 erp.acunetix…

这款Chrome 插件,使浏览器页面快速滑动到最底部和最顶部,并且还能...

前言 前几日我在使用谷歌浏览器,也就是chrome的时候,浏览一个内容很长的页面,由于页面上的内容有前后关联,所以我必须不停地切换到上面和下面。这非常不方便。使我非常抓狂。后来,我灵机一动,去谷歌浏览器的插件市场上搜索了一下有没有快速回到底部和顶部的插件,结果,还…

数据结构_链表_单向循环链表 双向链表的初始化、插入、删除、修改、查询打印(基于C语言实现)

一、单向循环链表的原理与应用 思考:对于单向链表而言,想要遍历链表,则必须从链表的首结点开始进行遍历,请问有没有更简单的方案实现链表中的数据的增删改查? 回答:是有的,可以使用单向循环的链表进行设计,单向循环的链表的使用规则和普通的单向链表没有较大的区别,需…

『模拟赛』多校A层冲刺NOIP2024模拟赛19

『模拟赛记录』多校A层冲刺NOIP2024模拟赛19Rank byd CSP 之后就没场切过题😡😡😡A. 图书管理 签,又寄了。 这种题直接做复杂度算着不对的话大概率就是要拆分贡献了。赛时用对顶堆维护的中位数,卡常到极致在 \(n=10^4\) 时要跑 1.2s。 感觉卡常有用所以写下来:发现如果…

WSL 挂载虚拟磁盘

为了扩展 WSL 虚拟机的大小,可以在 D 盘创建一个虚拟硬盘文件作为 WSL 虚拟机的数据盘。创建虚拟硬盘文件。打开磁盘工具,点击 操作 > 创建 VHD 打开虚拟硬盘创建菜单,创建一个虚拟硬盘文件:挂载虚拟硬盘。打开终端(管理员),运行下面的命令找到刚刚新建的虚拟磁盘: …

HTML - 1

HTML - 1 基础内容 标签与标签属性 属性不区分大小写 (推荐小写)可以用双引号 也可以用单引号 (推荐双引号)重复的属性,后边的会失效通用属性:id: 给标签打上唯一标识 (head html meta script style title不能加) ​ class:指定标签类名,与样式配合 ​ style:…

umount的时候target is busy

https://blog.csdn.net/u013409979/article/details/139867156

关于JVM调优与实践

1.如何开始JVM调优 ——tomcat内部署war包 修改TOMCAT_HOME/bin/catalina.sh文件JAVA_OPTS="-Xms512m -Xmx1024m"——linux环境下jar包启动springboot项目 启动时使用nohup java -Xms512m -Xmx1024m -jar x.jar --spring.profiles.active=prod &nohup:在系统后天…