[ 赛后总结 ] CSP-J 2022
前言
今年没考好,估分 100+60+0+10=170pts ,大概能混个2=,没什么用。
这下好了,期中也砸了,已经排到全校 30 开外了,果然鱼和熊掌不可兼得,况且我双双落空,接下来怕是想搞也搞不了了,写完这篇,卷 whk 去。
语文 | 数学 | 英语 | 物理 | 化学 | 历史 | 政治 | total |
---|---|---|---|---|---|---|---|
108 | 145 | 139 | 58 | 80 | 97 | 78 | 705 |
正文
T1 [CSP-J 2022] 乘方
简化题意:给出两个正整数 \(a,b(a,b\leqslant10^9)\) ,检查 \(a^b(a^b\leqslant10^{18})\) 是否超出 int 类型,即 \(10^9\) 或 \(2^{31}-1\) ,超过则输出 -1,否则输出该值。
乱搞100pts?
乍一看,不知道是不是有人跟我一样,想到 pow 函数。(可能你们都第一时间放弃这个想法)
于是乎我立马把程序打了出来,当然,还需考虑一下 pow 溢出出现负数的情况。(但后来 tx 说难道不会负负得正吗,我想都溢出了还会继续调用函数计算吗,eee)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const long long inf=1e9;
long long a,b,ans;
int main()
{
//freopen("pow.in","r",stdin);
//freopen("pow.out","w",stdout);
cin>>a>>b;
ans=pow(a,b);
if(ans>inf || ans<0) cout<<-1;
else cout<<ans;
return 0;
}
后来洛谷和小图灵实测都是 AC ,我也很恍惚,有人说要特判 \(a=1\) 的情况,但我的代码也没超时,有点玄学。
正解
其实就是暴力,一个 for 循环加特判解决的事,考场上我以为它会超时,后来想想,其实不然,只需每次做跟着判断即可。
∵ \(10^9=2^{31}-1\) ,
∴当 \(a=2\)时,此做法循环次数最多 30 次,
则当 \(2<a\leqslant10^9\),次数只会趋近于 1 。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf=1e9;
ll a,b;
int main()
{
//freopen("pow.in","r",stdin);
//freopen("pow.out","w",stdout);
cin>>a>>b;
if(a==1)
{
cout<<1;
return 0;
}
ll ans=a;
for(int i=1;i<=b-1;i++)
{
ans*=a;
if(ans>inf)
{
cout<<-1;
return 0;
}
}
cout<<ans;
return 0;
}
当然,也有人说可以用快速幂,以后学了再来补。
T2 [CSP-J 2022] 解密
给定一个正整数 \(k(k\leqslant10^5)\) ,有 \(k\) 次询问,每次给定三个正整数 \(n_i,d_i,e_i(n_i\leqslant10^{18})\) ,求两个正整数 \(p_i,q_i\) ,使 \(n_i=p_i\times q_i~,~d_i\times e_i=(p_i-1)(q_i-1)-1\) ,为了统一,应当保证 \(p_i\leqslant q_i\) 。
其中,\(d_i\times e_i\leqslant 10^{18}\),设 \(m=n-d\times e+2\) ,则有 \(m\leqslant10^9\)。
正解
一道数学题。良心的是,\(m\) 的定义是原题就有的,这引导我们的思路。
分别设等式为1,2式,可变形2式:
\]
\]
\]
即$$p+q=m$$
联立1得:
pq=n
\\p+q=m
\end{cases}
\]
这下好办了,带入近似解一个一元二次方程,用公式法即可。
根据方程组,可得:
\]
\]
\]
显然按要求, \(p=q_1,q=q_2\) 。
至此,得到答案的由来,当然还需注意一些问题:
众所周知,当 \(\Delta<0\) 时,是没有实数根的,此处要提前特判;
得到两个实数根后,显然要判断是否同时满足两个等式;
特别注意(其实我在这里想了很久才明白),两个实数根要求是正整数,说明浮点类型的解也是不合法的。首先,能确定 \(n,d,e,p,q,\Delta\) 都是
long long
,但 \(\sqrt{\Delta}\) 就可能出现小数,那么它就有必要是double
类型的。显然,如果 \(\sqrt{\Delta}\)是浮点数,则 \({(\sqrt{\Delta})}^2 \not =\sqrt{\Delta}\),必定会有精度偏差,是整数则不然。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int k;
ll n,e,d,m,p,q;
int main()
{
//freopen("decode.in","r",stdin);
//freopen("decode.out","w",stdout);
cin>>k;
while(k--)
{
cin>>n>>d>>e;
m=n-e*d+2;
ll delta=m*m-4*n;
if(delta<0)
{
cout<<"NO"<<endl;
continue;
}
double tmp=sqrt(delta);
p=(m-tmp)/2;
q=(m+tmp)/2;
if(tmp*tmp!=delta || p+q!=m || p*q!=n) cout<<"NO"<<endl;
else cout<<p<<' '<<q<<endl;
}
return 0;
}
其实,我考场上写的不是正解,从估分看的出来,是一个只能拿 60pts 的超时程序。
我当时想到了这个 \(O(k\times \sqrt{n})\) 的暴力,想着拿个 60pts 算了,因为我虽然 whk 的数学还不错,但 \(OI\) 的数论真的把我难吐了,我一直都很抵制做数论题(以后要改了),所以就......没想到正解就是这学期学的,呜呜呜~
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int k;
ll n,e,d,p,q;
int main()
{
//freopen("decode.in","r",stdin);
//freopen("decode.out","w",stdout);
cin.tie(0);
cout.tie(0);
cin>>k;
while(k--)
{
cin>>n>>d>>e;
ll add=n-e*d+2;
bool flag=false;
if(n>1e9)
{
for(int i=1e7;i<=sqrt(n);i++)
//PS:当时以为能降低一点大数据的复杂度,其实并没用
{
if(n%i==0)
{
p=i;
q=n/i;
if(p+q==add)
{
cout<<p<<' '<<q<<endl;
flag=true;
break;
}
}
}
}
else
{
for(int i=1;i<=sqrt(n);i++)
{
if(n%i==0)
{
p=i;
q=n/i;
if(p+q==add)
{
cout<<p<<' '<<q<<endl;
flag=true;
break;
}
}
}
}
if(flag) continue;
cout<<"NO"<<endl;
}
return 0;
}
还有用二分做的,我感觉没这必要了吧。
T3 [CSP-J 2022] 逻辑表达式
简化题意:给定一个逻辑表达式字符串 \(s\) ,规定在运算时,括号内的部分先运算;两种运算并列时,
&
运算优先于|
运算;同种运算并列时,从左向右运算。
计算它的值。并且统计两种“短路”的次数,定义&
短路形如0&x
,|
短路形如1|x
,特别注意,如果某处“短路”包含在更外层被“短路”的部分内则不被统计。
其中,长度 \(\leqslant 10^6\) ,保证没有重复的括号嵌套,仅含有字符
0
1
&
|
(
)
。
正解
鸽。
T4 [CSP-J 2022] 上升点列
简化题意:在二维平面中,给定 \(n\) 个点和 \(k\) 个自由添加的点,求在 \(n+k\) 个点中,最长子序列的点数,定义该序列为相邻点距离为1,且横纵坐标不下降。
其中,\(1 \leq n \leq 500\),\(0 \leq k \leq 100\)。对于所有给定的整点,其横纵坐标 \(1 \leq x_i, y_i \leq {10}^9\),且保证所有给定的点互不重合。对于自由添加的整点,其横纵坐标不受限制。
测试点编号 | \(n \leq\) | \(k \leq\) | \(x_i,y_i \leq\) |
---|---|---|---|
\(1 \sim 2\) | \(10\) | \(0\) | \(10\) |
\(3 \sim 4\) | \(10\) | \(100\) | \(100\) |
\(5 \sim 7\) | \(500\) | \(0\) | \(100\) |
\(8 \sim 10\) | \(500\) | \(0\) | \({10}^9\) |
\(11 \sim 15\) | \(500\) | \(100\) | \(100\) |
\(16 \sim 20\) | \(500\) | \(100\) | \({10}^9\) |
乱搞25pts
我打个暴搜都只能骗到这点分,可见我水平是何等的低。(甚至是优化了考场10pts的程序)
思路羞于多讲,就是分了 \(k=0\) 的特殊情况,一般地,贪心找最左下角点开始查找关于横纵坐标的最长不下降序列;特别地,找最大符合前文性质的联通快。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=510,M=100;
int n,k;
struct node
{
int X,Y;
}a[N];
int dx[2]={1,0};
int dy[2]={0,1};
int G[M+10][M+10],ans=-1;
bool vis[M+10][M+10];
bool cmp(node a,node b)
{
if(a.X==b.X) return a.Y<b.Y;
return a.X<b.X;
}
void dfs(int x,int y,int now_k,int cnt)
{
//if(cnt<ans) return;
if(now_k>k)
{
ans=max(ans,cnt);
return;
}
//cout<<x<<' '<<y<<' '<<now_k<<' '<<cnt<<endl<<endl;
for(int i=0;i<2;i++)
{
int tx=x+dx[i],ty=y+dy[i];
if((tx>=1&&tx<=M&&ty>=1&&ty<=M) && !vis[tx][ty])
{
vis[tx][ty]=true;
if(G[tx][ty]==1)
{
dfs(tx,ty,now_k,cnt+1);
}
else
{
dfs(tx,ty,now_k+1,cnt+1);
}
//vis[tx][ty]=false;我服了,找了一个小时
}
}
}
void dfs2(int x,int y,int cnt)
{
ans=max(ans,cnt);
for(int i=0;i<2;i++)
{
int tx=x+dx[i],ty=y+dy[i];
if((tx>=1&&tx<=M&&ty>=1&&ty<=M) && !vis[tx][ty] && G[tx][ty]==1)
{
vis[tx][ty]=true;
dfs2(tx,ty,cnt+1);
vis[tx][ty]=false;
}
}
}
int main()
{
//freopen("point.in","r",stdin);
//freopen("point.out","w",stdout);
cin.tie(0);
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>a[i].X>>a[i].Y;
G[a[i].X][a[i].Y]=1;
}
sort(a,a+n+1,cmp);
//cout<<a[1].X<<' '<<a[1].Y; return 0;
if(k>0)
dfs(a[1].X,a[1].Y,0,1);
else
{
int maxn=-1;
for(int i=1;i<=n;i++)
{
memset(vis,false,sizeof(vis));
ans=-1;
dfs2(a[i].X,a[i].Y,1);
maxn=max(maxn,ans);
}
cout<<maxn;
return 0;
}
cout<<ans;
return 0;
}
正解
一道 DP 。其实我一开始看到这道题类似 LIS ,就想到了,但想不出方程,eee。(话说我当时为什么不直接拿它当 LIS 模板做,这样还能拿 65pts ,失策了)
首先,考虑对 \(n\) 个节点排序,使其从前往后访问横纵坐标不降(即访问顺序为 \(Oxy\) 中从 \(O\) 出发, \(y=kx(k>0)\) 的第一象限图像),保证转移时无后效性。
状态
可以类比增加一维,用 \(f[i][l]\) 表示以 \(a_i\) 为结尾,已经插入 \(l\) 个额外点的最长不下降子序列的最大点数。阶段
- 显然要对 \(a_i(1\leqslant i \leqslant n)\) 查找;
- 当前点的长度是由之前的点转移而得,∴要对 \(a_j(1\leqslant j<i)\) 查找;
- 对于区间 \([a[i],b[i]]\) ,中间可以插入 \(len(下界)\) 到 \(k\) 个额外点,∴要枚举所有可行的插入方案。
对于 \(len\) ,已知两点坐标,可知两点之间最少需要的额外点:
\]
- 方程
综上易得:
\]
- 边界
我们初始无法确定 \(n\) 个点之间的关系,但可以确定每个点和 \(k\) 个点的关系,相当于,在一开始, \(k\) 个点可以分别和每个点链接组成保证合法的序列,则有:
\]
- 目标
显然,插入所有 \(k\) 个点为最优解,即:
\]
#include<bits/stdc++.h>
using namespace std;
const int N=510,K=110;
struct node
{
int x,y;
}a[N];
int n,k,f[N][K],ans=-1;
bool cmp(node p,node q)
{
if(p.x==q.x) return p.y<q.y;
return p.x<q.x;
}
int main()
{
//freopen("point.in","r",stdin);
//freopen("point.out","w",stdout);
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i].x>>a[i].y;
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++)
for(int j=0;j<=k;j++) f[i][j]=j+1;
for(int i=2;i<=n;i++)
for(int j=i-1;j>=1;j--)
{
if(a[j].y>a[i].y)continue;//注意,因为cmp函数按x优先
int len=(a[i].x-a[j].x)+(a[i].y-a[j].y)-1;
for(int l=len;l<=k;l++) f[i][l]=max(f[i][l],f[j][l-len]+len+1);
}
for(int i=1;i<=n;i++)
ans=max(ans,f[i][k]);
cout<<ans;
return 0;
}
PS
update:2022.11.8
CCF官方数据修正: 100+60+0+20=180pts , \([15.2\%,16.6\%]\) ,还是很慌。update:2022.11.17
喜提1=,HN分数线170,压线过。
[ 赛后总结 ] CSP-J 2022的更多相关文章
- CSP J/S 初赛总结
CSP J/S 初赛总结 2021/9/19 19:29 用官方答案估计 J 涂卡的时候唯一的一支 2B 铅笔坏了,只能用笔芯一个个涂 选择 \(-6\ pts\) 判断 \(-3\ pts\) 回答 ...
- 【游记】CSP J/S 2019 游记
J 组 \(2:30\)开始, \(2:13\)还在酒店的我看了看手表...飞奔考场. T1 数字游戏 秒切. 下午某中学某大佬说可用线性基(%) T2 公交换乘 用单调队列思想,秒切. T3 纪念品 ...
- CSP/S 2022 游寄
初赛 HN 初赛分数线好像大 \(32\) 分左右,通过率极高!本人弱弱的拿了 \(60.5\) 分(周围的同学平均分 \(>80\).) Day -1 这一天晚上,我背了背 dijkstra, ...
- CSP J/S 2019受虐记
一枚蒟蒻的游记~ 提高组DAY1 不是说每场考试都有一道签到题吗 那我tm读了三遍题硬是没找到一道水题是怎么回事(是我太弱了吗) 没办法,硬着头皮做T1 暴力写法...期望得分30pts 于是...在 ...
- [游记]2020/CSP - S总结
2020 / C S P − S 总 结 2020/CSP - S总结 2020/CSP−S总结 这年的 C S P CSP CSP考的不是很理想,本来稳进的 C S P − J CSP-J CSP− ...
- 2022 CSP-J 游记
Day − ∞ -\infty −∞ 在家里跟父母约定 "只要csp-j一等奖,手机随你挑!" 对于一个没有手机的初中生废物,这个约定显然勾引了我 刷题! 刷题! 再刷! 刷废-- ...
- emacs考场短配置
(set-background-color "gray15") (set-foreground-color "gray") ;;设置颜色 (global-set ...
- OI记录
这里是蒟蒻xsl的OI记录. 2017 2017.03.?? 开始接触OI 2017.10.14 参加NOIP2017普及组初赛,踩着分数线进入了复赛 2017.11.11 参加NOIP2017普及组 ...
- noi linux 2.0 体验
一.起因 下午,我打开 noi 官网准备报名 csp j/s,一看官网展板:"noi linux 2.0 发布" 我就兴奋了起来.(9 月 1 日起开始使用, 也就意味着 csp ...
- SpringBoot使用poi实现导出excel
//实体类 //导出的数据的实体 public class User { private String id; private String name; private String year; // ...
随机推荐
- Python编程之子进程管理(subprocess)详解
引言 在写程序时,我们无法避免需要运行外部程序,相较于功能比较简单的os.system(),更加倾向于使用subprocess模块来执行外部程序. 模块介绍 subprocess.run() 使用su ...
- prometheus监控实战
第一节.环境和软件版本 1.1.操作系统环境 主机ip 操作系统 部署软件 备注 192.168.10.10 Centos7.9 Grafana.Pushgateway.Blackbox Export ...
- 【算法】基础DP
参考资料 背包九讲 一.线性DP 如果现在在状态 i 下,它上一步可能的状态是什么. 上一步不同的状态依赖于什么. 根据上面的分析,分析出状态和转移方程.注意:dp 不一定只有两维或者一维,一开始设计 ...
- js中通过正则表达式验证邮箱是否合法
文章目录 1.效果展示 2.问题描述 3.代码实现 1.效果展示 2.问题描述 当用户在输入框输入邮箱后.点击验证邮箱按钮.系统给出提示信息. 3.代码实现 <!DOCTYPE html> ...
- sql面试50题------(11-20)
文章目录 11.查询至少有一门课与学号为'01'的学生所学课程相同的学生的学号和姓名 12.查询和'01'号同学所学课程完全相同的其他同学的学号 13.查询两门及其以上不及格课程的同学的学号,姓名及其 ...
- 2、yaml配置文件当中的坑(数字的定义和支持进制书写格式)
6.进制数的转换 6.1.问题回顾 我记得我刚刚开始使用SpringBoot的时候,有一天在做到SpringBoot整合第三方技术的时候 我刚好在那天学习到整合Mybatis,做Web项目嘛,不连数据 ...
- 关于Redis的,你了解多少?来看看我的笔记
Redis 概述 Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据 ...
- 抓包整理————ip 协议一[十二]
前言 简单介绍一下ip协议. 正文 先来看下ip协议在网络层的哪一层: 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层 ip 层就在网络层: 其实很好想象哈,就是因为每台机器起码有一个ip ...
- 嵌入式-C语言基础:快速选择排序实现从大到小排序
#include<stdio.h> int main() { /*简单选择排序:从大到小:一共比较sizeArr-1轮,每一轮的第一个数是arr[i],第一个数依次和它后面的每个数比较*/ ...
- CSP-J2022 题解报告
\(CSP-J2022\) 题解报告 \(T1\) 乘方: 发现 \(2^{32}>10^9\),所以这个题只需要特判 \(a=1\) 的情况为 \(1\),其他直接枚举再判断即可. Code: ...