当前位置: 首页 > news >正文

上海市计算机学会竞赛平台2023年7月月赛丙组题目解题报告

上海市计算机学会竞赛平台2023年7月月赛丙组题目解题报告

T1 先行后列(孙誉文)

题意

第一列第二列m
第一行12m
第二行m+1m+22m
第三行2m+12m+23m
nnm

给我们2个数表示表格的m和n,再给我们1个数(我们设为int变量c),让我们输出这个数所在的行与列,输出先行后列。

分析

1)观察这个表格我们会发现表格含有规律,c%m的结果为c所在的数列,但是我们注意有1个特判:当c%m结果为0时,c所在数列便是第m列。上述逻辑可以用1个if语句来实现。并将所在列赋值给变量b.

2)在得到所在列b的情况下,我们可以借此来推算出c所在的行。随后便可以发现c/m+1的结果就是c所在的行,但是这里也要有1个特判:当c在m列时c/m的结果就已经是c所在的行,这里无需加1。同1这里也可以用if语句来完成。if语句中把所在行赋值给变量a。

3)以上逻辑会发现题目给的n毫无用处,所以可以不定义n变量。只要把读入写为cin>>m>>m>>c;2次读入m,最后的读入会把之前的读入覆盖。(不过保留n也不影响程序)

代码

#include <bits/stdc++.h>
using namespace std;int m, c, a, b;
int main(){cin>>m>>m>>c;if (c%m==0) b=m;else b=c%m;if (b==m) a=c/m;else a=c/m+1;cout<<a<<" "<<b<<endl;
}

T2 兔子序列(陈致臻)

题目描述

序列 fi 的定义如下:

  • f1=1
  • f2=a
  • i>2 时,fi=fi−1+fi−2

给定一个 k,请问找到 j*,j 满足

fjk<fj+1

输入格式
  • 第一行:单个整数 a
  • 第二行:单个整数 k
输出格式
  • 单个整数 j
数据范围
  • 1≤a≤20
  • 1≤k≤1,000,000,000
样例数据

输入: 1
10

输出: 6

说明: 10 介于 第6个数 与 第7个数 之间

分析

本题为斐波那契数列,不过是把第二个数由1换成了a而已,函数内加不加vh数组都行,这里加了以保证不超时

代码1
#include<bits/stdc++.h>
using namespace std;int s;
long long a,k,ans,vh[100010];int f(int s){if(vh[s]!=-1) return vh[s];if(s==1) return vh[s]=1;if(s==2) return vh[s]=a;return vh[s]=f(s-1)+f(s-2);}int main(){memset(vh,-1,sizeof(vh));cin>>a>>k;for(int i=1;i<=100000;i++){if(f(i)<=k&&k<f(i+1)){ans=i;break;}}cout<<ans<<endl;return 0;
}
代码2
#include<bits/stdc++.h>
using namespace std;int s;
long long a,k,ans,vh[100010];int f(int s){if(s==1) return 1;if(s==2) return a;return f(s-1)+f(s-2);}int main(){memset(vh,-1,sizeof(vh));cin>>a>>k;for(int i=1;i<=100000;i++){if(f(i)<=k&&k<f(i+1)){ans=i;break;}}cout<<ans<<endl;return 0;
}

T3 数轴旅行(一)(顾浩骞)

题目描述

在数轴上,一共有 n n n 个景点,坐标分别为 x 1 , x 2 , x 3 , . . . . , x n x_1 ,x_2,x_3 ,....,x_n x1,x2,x3,....,xn
你初始在 x = 0 x=0 x=0位置,每次你可以往左 d d d 个单位或往右 d d d 个单位,请问为了访问到每一个景点, d d d 最大可以取到多少?

输入格式

输入共两行:
第一行,第一个正整数 n n n
第二行, n n n 个整数 x 1 , x 2 , x 3 , . . . . , x n x_1 ,x_2 ,x_3 ,....,x_n x1,x2,x3,....,xn

输出格式
输出一行,表示答案

数据范围
对于 30 % 30\% 30% 的数据, 1 ≤ n ≤ 10 1≤n≤10 1n10
对于 60 % 60\% 60% 的数据, 1 ≤ n ≤ 1 0 3 1≤n≤10^3 1n103

对于 100 % 100\% 100%的数据, 1 ≤ n ≤ 1 0 5 , − 1 0 9 ≤ x 1 , x 2 . . . x n ≤ 1 0 9 1≤n≤10^5,-10^9≤x_1,x_2...x_n≤10^9 1n105,109x1,x2...xn109

样例数据
输入:

2
-4 4

输出:

4

输入:

3
-2 4 10

输出:

2

分析:本题就相当于求 n n n个数的最大公约数,知道三个的最大公约数是gcd(gcd(x,y),z),那么以此类推,就类似于递推,但是要处理 n = 1 n=1 n=1的情况,可以给 n + 1 n+1 n+1,也就是 n = 2 n=2 n=2,赋一个值,为 n = 1 n=1 n=1的倍数,当 n > 1 n>1 n>1,这个 n + 1 n+1 n+1用不到,当 n = 1 n=1 n=1,用 a 1 , a 2 a_1,a_2 a1,a2求最小公倍数,自然为 a 1 a_1 a1

代码:100分

#include<bits/stdc++.h>
#define int long long
using namespace std;int n,a[100010],ans;int gcd(int x,int y){return y?gcd(y,x%y):x;}//求最大公约数signed main(){cin>>n;for(int i=1;i<=n;++i){cin>>a[i];a[i]=abs(a[i]);}a[n+1]=a[1]*2;//刚讲的特判ans=gcd(a[1],a[2]);for(int i=3;i<=n;++i) ans=gcd(ans,a[i]);//n<3时,这个循环不会执行,但是n=2时上面已经求了最大公约数,但n=1时没第二个数与他求,所以才加了个特判cout<< ans << endl;return 0;
}

T4 模糊匹配(二)(杨晓赫)

内存限制: 256 Mb时间限制: 1000 ms
题目描述
有两个仅包含大写英文字母的字符串 S,T,且字符串 T 是 S 的一个子串。
但由于字符串 S 字迹模糊不清,其某些位置上的字符没有办法进行辨认,这些模糊的位置,用 ? 代替,我们将这个字符串称为S 。
现给定字符串 S ,T,请你求出,满足条件的所有可能的原字符串 S 中,字典序最小的一个。
输入格式
输入共两行:
第一行,一个字符串表示 S
第二行,一个字符串表示 T
输出格式
输出共一行,一个字符串表示答案
数据范围
设 ∣S∣,∣T∣ 分别为字符串 S,T 的长度
对于 30%的数据1≤∣T∣≤∣S∣≤10
对于 60%的数据,1≤∣T∣≤∣S∣≤10^2
对于 100%的数据,1≤∣T∣≤∣S∣≤10^4
数据保证存在字符串 S 满足条件

为保证字符串字典序最小,所有问号应尽可能填’A’,所以若T对应的S上部分没有’?‘或问号对应的是’A’,则应优先填它。
若无满足条件的,为保证字典序小,应从后往前找,尽可能让’?‘在前,方便填’A’。

#include <bits/stdc++.h>
using namespace std;string s,t;int main(){cin>>s>>t;bool f=true,fl=true;int l=s.size(),l1=t.size();for(int i=l-1;i>=0;--i){int z=i,m=l1-1;while(s[z]==t[m]||(t[m]=='A'&&s[z]=='?')){if(m==0){fl=false;break;}z--;m--;		}}if(fl){for(int i=l-1;i>=0;--i){int k=i,y=l1-1;while(s[k]==t[y]||s[k]=='?'){if(y==0){f=false;for(int j=i;j>=i-l1+1;--j){if(s[j]=='?'){s[j]=t[l1-1-i+j];}}break;}k--;y--;		}if(f==false)break;}
}for(int i=0;i<=l-1;++i){if(s[i]=='?'){cout<<"A";continue;}cout<<s[i];}return 0;
}

T5 排列排序(高国皓)

内存限制: 256 Mb时间限制: 1000 ms
题目描述
如果一个整数序列 a 1 , a 2 , … , a n a_1,a_2 ,…,a_n a1,a2,,an 的每个数字都在 1 到 n 之间,且没有两个数字相等,则称这个序列为全排列。例如1,3,2 以及 4,3,2,1 都是全排列。
我们将所有的全排列排序,定义全排列 a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,,an b 1 , b 2 , … , b m b_1,b_2,…,b_m b1,b2,,bm 的排序先后关系如下:
如果 n < m n<m n<m,则 a 序列更靠前
如果 n > m n>m n>m,则 b 序列更靠前
如果 n = m n=m n=m,则以字典序规则比较 a 序列与 b 序列,字典序更小的序列更靠前。
根据上述定义,可以得到
第 1 个全排列是 1
第 2 个全排列是 1 2
第 3 个全排列是 2 1
第 4 个全排列是 1 2 3
给定 k k k,请输出第 k k k 个全排列。
输入格式
单个整数:表示 k k k
输出格式
单独一行:表示第 k k k 个全排列
数据范围
30% 的数据 1 ≤ k ≤ 1000 1≤k≤1000 1k1000
60% 的数据 1 ≤ k ≤ 1 , 000 , 000 1≤k≤1,000,000 1k1,000,000
100% 的数据 1 ≤ k ≤ 1 0 15 1≤k≤10^{15} 1k1015
样例数据
输入:
5
输出:
1 3 2
说明:

根据上述定义可知全排列 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an 中的填数方法有 A n n A^n_n Ann( n ! n! n!) 种,更通俗地说,长度为 n n n 的全排列的个数有 n ! n! n! 个。
那么已知 k k k ,那么不断用 k k k 减去 1 ! , 2 ! , 3 ! , . . . , c n t ! 1!,2!,3!,...,cnt! 1!,2!,3!,...,cnt!直至结果在保证为正的情况下无法再减,那么 c n t cnt cnt 就是第 k k k 个全排列的位数,假设下列代码所用变量已经定义,最终可以求出第 k k k 个全排列是位数为 p o s pos pos 的全排列中的第 k k k (两个 k k k 不一样)个,其中 i i i 存放的是位数(即当前阶乘的参数), s s s 存放阶乘之和, l a s t last last 存放上一个的阶乘(即 ( i − 1 ) ! (i-1)! (i1)! )。

int i=0;
while(++i){s+=last*i;if(s>k){k=k-s+last*i;pos=i;s=last*i;break;}last*=i;}

当我们知道它是位数为 p o s pos pos 的全排列中的第 k k k 个时,而 s s s 表示 p o s ! pos! pos!,我们可以确定第一位,因为第一位有 p o s pos pos 种可能,而总计有 p o s ! pos! pos! 种可能,所以每一种 p o s pos pos 的可能性都对应着 ( p o s − 1 ) ! (pos-1)! (pos1)! 种可能,而它是第 k k k 种,所以第一位是第 k / ( s / p o s ) k/(s/pos) k/(s/pos) (向上取整)个数字。假设第一位是第 c c c 个数字,去掉前面的 c ∗ ( s / p o s ) c*(s/pos) c(s/pos) 种可能,剩下的 k − ( c − 1 ) ∗ ( s / p o s ) k-(c-1)*(s/pos) k(c1)(s/pos) 就是它在长度为 p o s − 1 pos-1 pos1 的全排列中的位置。
然后设计递归。注意我是第…个数字,而不是…数字。因为当有的数字已经被使用后,不能再次使用,必须继续向后找。

void f(int pos,int s,int k)

p o s pos pos 表示位数,当其等于1时不再递归; s s s 表示 p o s ! pos! pos! 用于计算可能性数量,注意实时的更新; k k k表示的是位次,用于每次输出剩余的首位(即第 总位数 − p o s + 1 总位数-pos+1 总位数pos+1 位)。
至于计算第 x x x 个数字,应当使用 v h vh vh 数组进行标记,如果使用过了,即继续查找。

int i=0,cnt=(k+s/pos-1)/(s/pos);
while(cnt--)if(vh[++i])++cnt;
cout<<i<<" ";

最后说明:因为没有仔细估计题目数据,数组就开到了10000000,具体大家可以算一算 1 0 15 10^{15} 1015 1 ! + 2 ! + 3 ! + . . . + n ! 1!+2!+3!+...+n! 1!+2!+3!+...+n!中的 n n n 值,最终算法复杂度为 O ( n 2 ) O(n^2) O(n2)(最坏情况)。

#include <bits/stdc++.h>
#define int long long
using namespace std;int k,s,last=1,pos,i;
bool vh[10000000];void f(int pos,int s,int k){int i=0,cnt=(k+s/pos-1)/(s/pos);int c=cnt;while(cnt--)if(vh[++i])++cnt;cout<<i<<" ";vh[i]=1;if(pos>1)f(pos-1,s/pos,/*k-(c-1)*(s/pos)*/k%(s/pos)?k%(s/pos):s/pos);//注释中是第二种参数写法
}signed main(){cin>>k;while(++i){s+=last*i;if(s>k){k=k-s+last*i;pos=i;s=last*i;break;}last*=i;}f(pos,s,k);return 0;
}

相关文章:

  • Java中常见的锁synchronized、ReentrantLock、ReentrantReadWriteLock、StampedLock
  • 【机器学习】朴素贝叶斯算法:原理剖析与实战应用
  • 深度补全网络:如CSPN++填补稀疏点云的深度信息
  • 修改 <li> 元素小圆点的颜色
  • 不连续数据区间天数累计sql
  • 手机投屏到电视方法
  • MongoDB导出和导入数据
  • 【大疆dji】边缘计算模块在大疆机场中的位置
  • Datawhale AI春训营】AI + 新能源(发电功率预测)Task1
  • nohup的使用
  • 2025年第16届蓝桥杯嵌入式竞赛学习笔记(十四):RTC实时时钟
  • ESB —— 企业集成架构的基石:功能、架构与应用全解析
  • 详细解释浏览器是如何渲染页面的?
  • 国网B接口协议图像数据上报通知接口流程详解以及上报失败原因(电网B接口)
  • Docker 网络详解:从 docker0 网桥到网络命名空间
  • 深入Docker核心技术:从Namespace到容器逃逸防御
  • OpenCV 04.19 练习
  • Python带有else子句的循环语句
  • 【漫话机器学习系列】210.标准化(Standardization)
  • docker 大模型
  • 宁波一季度GDP为4420.5亿元,同比增长5.6%
  • 年近九旬的迪图瓦,指挥能量比盛年更为强劲
  • 市场监管部门完成全国保健食品生产企业体系检查首轮全覆盖
  • 2025年度“沪惠保”将于4月22日开售,保费不变
  • 消息人士称哈马斯愿与以色列达成长期停火
  • 体坛联播|皇马补时绝杀毕尔巴鄂,利物浦最快下轮即可夺冠