ACM新生赛反思

12月16日举办了ACM新生赛,上周的热身赛发挥还可以拿到了500分,但是到了正式赛,题虽然比热身赛简单了,但是发挥的确很差,开始后大致看了一下题没有难题,都有思路,心里挺高兴的,感觉应该可以做出来起码七道题,在刚开始的一个小时完整ac了三道题,拿到了两个一血,心里沾沾自喜,就去做一道信息学奥赛一本通上的一道题第11题,特别经典的约瑟夫问题,开关灯,没怎么读题就去用暴力解决,用常规的数组进行模拟,没有注意给的数据是1e12之内的,数组如果开到1000000就可能报错,写好以后测试了多组数据感觉没问题就去提交了,结果不对,也没有再次读题,也没有转变思路,就去在原有的程序上进行改动,提交一直不对,心态有点爆炸,感觉怎么简单的问题自己还做不出来,比赛结束后发现是数据给的太大,然后想到了这类问题还可以用因子来操作,常规的思路是每个人来去对自己编号倍数的灯进行操作,用因子的话是用灯来挑人,人的编号是灯编号的因子的话就对这盏灯进行操作,如果有奇数个因子数这盏灯最后就是开的,偶数就是关的,这种思路只适用于灯数=人数。如果用因子来模拟的话从1开始遍历还是会超时,这时就要来优化,一个数的因子是成对出现,对于一个数 x,可以看成因子是成对拆分出的,
例如:12=112=34,
而完全平方数存在 x=aa 的情况,
例如:36=1
36=218=312=49=66,对于 6*6,两数相同,算一个因子,所以完 全平方数的因子个数是奇数个。
问题转化成,1-n 内有几个完全平方数。。。sqrt(n)个。。。。(1方1,2方,3方,sqrt(n)方);
附上题目和代码

灯 有 n 盏灯,编号为 1-n。第 1 个人把所有灯打开,第 2 个人按下所有编号为 2 的倍 数的开关(这些灯将被关掉),第 3 个人按下所有编号为 3 的倍数的开关(其中关 掉的灯将被打开,开着的灯将被关闭),以此类推。一共有 n 个人,问最后有多少 灯开着?

输入 第一行输入一个正整数 T (T<=10)
接下来 T 行,每行输入一个正整数 n(n<=1e12)。
输出 对于每个 n,输出 n 次操作后亮着的灯的数量。

样例
input 4
1
2
3
4

output 1
1
1
2

#include<bits/stdc++.h>
 using namespace std; 
 int T; int main()
  {    
   long long n;  
      cin>>T;   
        while(T--)  
           {        
            cin>>n;    
                 cout<<(int)(sqrt(n))<<endl;    
                 return 0;
                  } 

这道题没做出来以后就去做了第八题zzc的数字
这道题我当时的思路是暴力从1开始遍历写了一个判断位数是偶数的函数,一个是回文数的函数,

Description

如果一个数是回文数,并且这个数十进制的位数是偶数(不含前导零),我们就可以叫他zzc数,一个不含前导零并且从前往后读和从后往前读相同的数位回文数,然后在主函数内计数操作,测试虽然没问题但是可能是很多细节没有处理好导致wa,
题目如下
举个例子:12321和1221是回文数,123和12451不是回文数;1221是zzc数,12321不是zzc数。

Input

输入两个正整数k与p

k(1 <= k <= 1e7, 1<= p <= 1e9)

Output

请计算出前k小的zzc数的和,然后输出的和模p

Sample Input 1

2 100
Sample Output 1

33
Sample Input 2

5 30
Sample Output 2

15

思路:
第几个zzc数就是第几个正整数+第几个正整数的逆序,比如第12个zzc数就是1221,第123个zzc数就是123321;ac代码如下

#include <iostream> 
#include <vector>
#include <string.h>
 #include <stdio.h>
#include <unordered_map>   
#include <fstream> 
#include <stdlib.h>
#include <random>
using namespace std;
using ll = long long; 
ll get(ll i)
   {   
    ll res = i;    
    while (i) 
    {      
      res = res * 10 + i % 10;
              i /= 10;   
                          }   
            return res; 
                           }
  int main()
{    
  int k, p;    
  cin >> k >> p;  
    ll sum = 0;   
     while (k)
      {      
        sum += get(k);
         sum %= p;       
           k--;   
                       }   
         cout << sum << endl;
                          }

这道题没做出来后心态彻底爆炸,对后面的题也没心思去做了
奶糖在左,果糖在右
Description

在ACM集训队里,LWY学长和JH学姐是很好的朋友,从他们每天称呼对方“儿子”就能看出他们的关系非常的亲近。

而集训队里有一个糖果盒,有奶糖和水果糖两种,在盒子里排成一排,LWY学长很喜欢吃糖果,但是他的强迫症非常严重,他每次只拿两个相邻的糖果,而且必须是奶糖在左边,果糖在右边他才会拿,JH学姐每次他拿完糖果之后,都会在拿糖果的原处放新的糖果进去,但是她不想让LWY学长吃,就会故意果糖放左边,奶糖放右边。

显而易见,LWY学长没机会永远吃糖果了,他看了看糖果盒中糖果的排列,他想知道他最多还能吃多少颗糖果。

Input

第一行一个数字N(1<=N<=200,60%数据;1<=N<=100‘000,100%数据);

第二行是一个长度为N的字符串,M代表奶糖,F代表水果糖。

Output

一行一个数字,输出LWY学长最多能吃几颗糖果,数据可能过大,可以用long long int来存储结果。

Sample Input 1

5
MFMFM
Sample Output 1

6
题解: 这道题关键点是看出糖果交换的规律,每次交换实质上是果糖移动到左边奶糖的左边,也就是对于每 一颗果糖,它需要移动的次数是它左边奶糖的个数,所以答案只需要统计每一颗果糖右边奶糖的个数,再 加起来,就是交换次数,结果是交换次数乘以2,因为每次交换吃两颗糖。
附上ac代码

#include <bits/stdc++.h>
using namespace std;
int main()
{
int n,m=0,i,res=0;
string s; //string是字符串变量,char数组亦可
cin>>n;
cin>>s;
for(i=0;i<n;i++)
{
if(s[i]=='M')
{
m++;//发现奶糖,统计个数
}
else
{
res+=m;//发现果糖,记录个数
}
}
res*=2;
cout<<res<<endl;
}

你从前往后读,我从后往前
Description

给定一个字符串表示数学运算(加减运算),求此运算的结果。

例如:

给定字符串11+22+33,结果为:66

注意:字符串只由数字与加减号组成,相邻两个数字之间只有一个运算符,字符串以数字开头,以数字结尾

Input

输入为1行,为一个字符串

Output

输出一个整数,表示运算结果

Sample Input 1

11+22+33
Sample Output 1

66

#include<cstdio>
 #include<cstring> 
 using namespace std;
  const int MAX_LEN = 1000;
int main()
 {   
  char str[MAX_LEN];    
  int res = 0, nownum = 0, power = 1;    
  scanf("%s", str);    
  for(int i = strlen(str) - 1; i >= 0; i--)
  {        
  if(str[i] == '+' || str[i] == '-')
  {            
  switch(str[i])
  {                
  case '+':  
 res += nownum;                   
break;                
  case '-':                    
 res -= nownum;                   
 break;                
  res += nownum;           
                }           
    power = 1;           
    nownum = 0;       
                   }
else 
 {           
       nownum += (str[i] - '0') * power;           
       power *= 10;        
                      }

    } 
       res += nownum;    
       printf("%d\n", res);
        }

Lsd开奶茶店
Description

Lsd今天新开刚张了一个奶茶店,每杯奶茶五元钱,因为是刚开张,店里没有备零钱,只能通过顾客的买奶茶的钱找零了,现在只有五元、十元、二十元的纸币且每人只有一张,默认每个人只买一杯奶茶。

现在让你判断,有N个人在排队买奶茶(队形不能打乱),告诉你每个人手中有多大的面额,判断lsd是否能成功完成交易。(如果没有足够的钱找零,则表示不能成功交易)

Input

输入有两行,第一行为n,第二行有n个正整数

1 <= N <= 10000000

Output

能够成功交易则输出True,否则输出False

Sample Input 1

4
5 10 5 20
Sample Output 1

True
思路:使用模拟排队过程即可

#include <iostream>
#include <vector>
#include <string.h>
#include <stdio.h>
#include <unordered_map>
#include <fstream> 
#include <stdlib.h>
#include <random> 
using namespace std; 
using ll = long long;
 int main()
  {    
  int flag, n, m;   
   cin >> m;    
   for (int k = 0; k < m; ++k)
    {       
     cin >> n;        
     int m[3] = {0, 0, 0}; 
     flag = 0;             
     for (int j = 0; j < n; ++j) 
     {            
     int a;           
      cin >> a;           
       if (a == 5)
        {               
         m[0]++;         
            } 
            else if (a == 10)
             {               
              if (m[0] < 1)                   
               flag = 1;            
 else
  {                    
  m[1]++;                   
   m[0]--;               
       }           
           }
            else if (a == 20)
             {              
               if (m[1] >= 1 && m[0] >= 1)
               {                   
                m[1]--;
            m[0]--;                    
            m[2]++;              
              }
               else if (m[0] >= 3) 
               {                   
                m[0] -= 3;                    
                m[2]++;             
                   } 
                   else 
                   {                
                     flag = 1;             
                        }        
                            }       
                               }
        if (flag)        
            cout << "False" << endl;      
              else           
               cout << "True" << endl;  
                 } 
                 }

以上几道题是当时思路出错的,明明提及不过还是不转变思路,钻牛角尖,心态调整不好,导致值ac了一开始的三道题,在以后的比赛中一定不能出现这种情况,然后在未来的学习中努力把算法练好,在寒假进行一个月的集中训练,熟悉算法,寒假中把信息学奥赛一本通的题做完,然后争取在以后的省赛区域赛中拿到好名次

猜你喜欢

转载自blog.csdn.net/qq_43627087/article/details/85167684
今日推荐