暑假选拔赛

    技术2022-07-11  88

    以难度顺序排列

    文章目录

    1.摸鱼王的2468复读机分析代码 2.签到题分析代码 3.阶乘分析代码 4.ff爱组合数分析代码 5.合并滑稽分析错误代码AC代码 6.约数的个数分析代码 7.猜猜在哪里描述分析代码

    1.摸鱼王的2468复读机

    分析

    有规律的,除去第一位2的0次方个位数为1,其余以2 , 4,8 , 6为循环

    代码

    #include<iostream> using namespace std; int main() { long long n; cin>>n; int ans; if(n==0) ans = 1; else { switch(n%4) { case 0: ans = 6; break; case 1: ans = 2; break; case 2: ans = 4; break; case 3: ans = 8; break; } } cout<<ans<<endl; return 0; }

    2.签到题

    分析

    其实输出结果就是printf中的表达式,随便尝试一下就可以发现规律就是1,-1重复的循环,所以唯一的问题就是n过大,会超时

    代码

    #include<iostream> using namespace std; int main() { long long n; scanf("%lld",&n); if(n%2==0) cout<<-1<<endl; else cout<<1<<endl; return 0; }

    3.阶乘

    分析

    对于所有数,能够相乘得出10的倍数才能使结果的末位增加0,所以5成为一个非常重要的数字,对于每一个5,都需要一个2和它配对相乘才能得出10,所以所有2的倍数(2,4,6,8)都能够担此重任,把所有数分成5个一组,而对于阶乘而言,每一个5之前都会有至少两个2的倍数,所以一定够用。 需要注意的地方在于一些比较特殊的数字,例如25=5 * 5,这个数字能够拆分成为两个5,所以可以增加两个0,而50 = 2 * 5* 5也可以增加两个0,125 = 5 * 5 * 5,可以增加三个0,所以对于每一个数n!末尾的0应该表示为f(n) = n/5 + f(n/5),并且循环嵌套。

    代码

    #include<iostream> using namespace std; int main() { int n; int count=0; cin>>n; while(n) { n /= 5; count += n; } cout<<count<<endl; return 0; }

    4.ff爱组合数

    分析

    问题其实已经给出了公式,最复杂的部分就是怎么解决时间复杂度和答案溢出的问题,直接两个for循环嵌套就可以解决,然后计算结果的时候多多mod取余,以防溢出,虽然题目中好像没有这种情况。

    代码

    #include<iostream> #include<string.h> using namespace std; const long long MOD = 1e9 + 9; long long num[2002][2002]; void fun(); int main() { int T; memset(num,0,sizeof(num)); cin >> T; fun(); while (T--) { int n, m; cin >> n >> m; cout << num[n][m]<< endl; } } void fun() { for (int i = 0; i <= 2001; i++) { num[0][i] = 0; num[i][0] = 1; } for (int i = 1; i <= 2001; i++) { for(int j = 1; j <= i; j++) {//因为i一定大于等于j,结束条件减少无意义的计算 num[i][j] = (num[i-1][j]%MOD + num[i-1][j-1]%MOD) % MOD; } } }

    5.合并滑稽

    分析

    是一道贪心策略的题目,我觉得贪心没有固定的解题模式,就是一种理解方式。 本题的意图就是不断把一组数排序,然后取最小的两个数相加得出一个新的数放入数列中,之前的两个数抛去,并将相加的结果累加得出答案。 根据分析,其实用最简单的数组就能写,但是数据最大开到了10000,我算了一下,时间复杂度大概是10的8次方,亿级别以上基本不可能过,但是学校的平台上数据水了竟然过了。 所以必须使用优先队列,这里涉及STL内容(以后总结的话会更新)。首先将每个元素压入小根堆,在循环的时候不断的取头上的值,取两个作为最优值(a,b),最后再弹掉。结果就是不断累加两个元素(a,b),最后再把此次的和再压入小根堆。

    错误代码

    这是会超时的代码

    #include<iostream> #include<cstring> #include<algorithm> using namespace std; int num[10005]; int main() { int n; cin >> n; //memset(a,0,sizeof(a)); for (int i = 0; i < n; i++) { cin >> num[i]; } long long mx = 0; while (n > 1) { sort(num, num+n); num[0] += num[1]; mx += num[0]; n--; for (int i = 1; i < n; i++) { num[i] = num[i+1]; } } cout <<mx<<endl; return 0; }

    AC代码

    #include<queue> #include<iostream> #include<stdio.h> using namespace std; priority_queue<int,vector<int>,greater<int> >q;//优先队列定义小根堆 int main(){ int n,x; int ans=0;//一定记得初始化,因为没初始化卡了两次 cin>>n; for(int i=1;i<=n;i++){ cin>>x; q.push(x); } while(q.size()>=2){//终止条件 int a=q.top();//取头最优值 q.pop();//丢弃 int b=q.top(); q.pop(); ans += a+b;//最优值来源 q.push(a+b);//压入 } printf("%d\n",ans);//输出 return 0; }

    6.约数的个数

    分析

    这道题的意图就是求出1-N中所有数的约数个数,并依次相乘一个常数,最后求出相加的和,且为了防止数字过大溢出要约1e15,。 求约数可以使用数论中提到的方法–筛法求解,

    代码

    在这里插入代码片

    7.猜猜在哪里

    描述

    有一个很有意思的魔术

    桌子上有从左到右编号为1到n的n顶不透明的帽子,一开始只有1号帽子下面有一只兔子,魔术师会依次交换其中的m对帽子,也就是说每次把从左往右的第x个帽子和第y个帽子交换,其中x, y不相同,帽子下的兔子也会跟着帽子移动。

    由于魔术师神奇的手法,作为观众的你没有看到魔术师的部分交换操作,但你按顺序记下了一部分不一定连续的交换操作。对于每个你没看到的交换操作,我们假设魔术师会等概率地选择两个位置不同的帽子交换,请问所有操作结束以后,兔子在从左到到右第1, 2, …, n号帽子底下的概率分别是多少?

    分析

    代码

    Processed: 0.011, SQL: 9