zoukankan      html  css  js  c++  java
  • 2018年,牛客网小白月赛5

    第一次啊,补题,希望大佬批评。

    题目按我补题顺序来的。

    https://www.nowcoder.com/acm/contest/135#question

    H  题

    最大公倍数

    题意:给出两个数,求最大公倍数

    欧几里德算法算出最大公约数k;

    然后算出。最大公倍数即可

    代码如下:

    #include<iostream>
    #define ll long long
    using namespace std;
    ll gcd(ll a, ll b)
    {
     return b == 0 ? a: gcd(b, a%b);
    }
    int main()
    {
     ll n, m;
     cin >> n >> m;
     ll kk = gcd(n, m);
     cout << (n / kk)*(m / kk)*kk << endl;
     return 0;
    }

    J 题  time 

    题意:

    给出一个时间,比如23:32,得出不是它本生的上一个和下一个回文时间,(回文时间指的是:ab:ba这种格式)

    思路一:

    模拟:直接一分一分的减去,得到下一个回文时间,一分一分的加得到上一个时间。不过,要仔细些不然会在这里出错。                          然后,写一个回文的判断就可以了。

    代码如下:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int main()
    {
     int a, b,h,m;
     scanf("%d:%d", &a, &b);
     //上一个时刻
     h = a; m = b-1;
     while (1)
     {
      if (h == ((m % 10) * 10 + m / 10))
      {
       cout << h << ":" << m<<endl;
       break;
      }
      m--;
      if (m < 0)
      {
       m += 60; h--; if (h < 0)h += 24;
      }
     }
     h = a; m = b+1;
     while (1)
     {
      if (h == ((m % 10) * 10 + m / 10))
      {
       cout << h << ":" << m<<endl;
       break;
      }
      m++;
      if (m >= 60)
      {
       m -= 60; h++; if (h >= 24)h -= 24;
      }
     }
    }

    思路二:

    打表

    因为:回文时钟的种数只有16种(注意:06:60不符合)所以可以建一个结构体存下小时h和分m和总的分h*60+m;注意一下0:0是24*60所以注意一下就可以了,直接把所给的时间在这个数组中找一下第一个比它大的就行(注意:0:0)

    代码略

    I  题

    题意:

    给你一个数组存入数字,然后又n次操作,每次对 l 到 r 区域进行每个数字加或减去d。然后,输出x到y区域的所有数字之和。

    思路:

    例子:

    建一个数组记录操作数sum[ ]只操作一次:从4到6加7,则sum[4] + =7;sum[6+1] - =7;  然后就for (int i = 1; i <= n; i++)    sum[i] += sum[i - 1];  是不是在4到6之间,sum都是7了

    如果是4到6减去7, 则sum[4] - = -7;sum[6+1] + =7;然后就for (int i = 1; i <= n; i++)    sum[i] += sum[i - 1];  是不是在4到6之间,sum都是  -7 了.

    那么多组操作呢?

    先把这段代码放上来;

    while (m--)
     {
      scanf("%d%d%d%d", &a, &b, &c, &d);
      if (a == 0) sum[b] += d, sum[c + 1] -= d;
      else sum[b] -= d, sum[c + 1] += d;
     }
     for (int i = 1; i <= n; i++)
      sum[i] += sum[i - 1];

    是不是担心,这样会出错。其实不用的。刚刚一次操作是  sum[4] + =7;sum[6+1] - =7或则  sum[4] - = -7;sum[6+1] + =7  多组操作会影响每一组操作的独立性吗? 答案是不会。你可以把它看做是这样的代码;

    for (int i = 0; i < t; i++)
    {
     scanf("%d%d%d%d", &a, &b, &c, &d);
     if (a == 0) sum[i][b] += d, sum[i][c + 1] -= d;
     else sum[i][b] -= d, sum[i][c + 1] += d;
     for (int j = 1; j <= n; j++)
      sum[i][j] += sum[i][j - 1];
    }
    for (int i = 1; j <= n;j++)
    for (int j = 0; j < t; j++)
    {
     num[j] += sum[j][i];
    }

    但是,每一次的操作是独立的(相当于数学中数据等价一样),所以,就把多组操作一起处理了。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #define ll long long
    using namespace std;
    ll num[1000004], sum[1000004];

    ll ans = 0;
    int main()
    {
     int n, m, a,b,c,d, x,y;
     scanf("%d%d", &n, &m);
     for (int i = 1; i <= n; i++)
      scanf("%lld", &num[i]);
     while (m--)
     {
      scanf("%d%d%d%d", &a, &b, &c, &d);
      if (a == 0) sum[b] += d, sum[c + 1] -= d;
      else sum[b] -= d, sum[c + 1] += d;
     }
     for (int i = 1; i <= n; i++)
      sum[i] += sum[i - 1];
     scanf("%d%d", &x, &y);
     for (int i = x; i <= y; i++)
      ans += sum[i]+num[i];
     cout << ans << endl;
    }

    F  题

    这个题让我想起了各种切割(数学)

    总结一下:

    n条直线最多分平面问题

    n(n+1)/2+1;

    折线分平面

    2*n^2-n+1;

    封闭曲线分平面

    n^2-n+2;

    平面分割空间

    (n^3+5n)/6+1;

    N个三角形分割平面

    3*n^2-3*n+2

    在一个圆上有n个点,将n个点两两相连分割圆

    1 + n*(n - 1) / 2 + n*(n - 1)*(n - 2)*(n - 3) / 24

    具体证明就不说了,(线段和射线决定对应一个区域(特别的复杂的都是递推了))

    题意:就不用说了

    思路:直接套数学公式

    代码如下:

    #include<iostream>
    #define ll long long
    using namespace std;
    int main()
    {
     ll n;
     while (cin >> n)
     {
      cout << 1 + n*(n - 1) / 2 + n*(n - 1)*(n - 2)*(n - 3) / 24 << endl;
     }
     return 0;
    }

    A  题      无关

    题意:给你一个集合,集合中元素都是素数(其实只要两两互质就行),问你在一个从  l 到 r 范围中,有几个数不被集合中的任何一个元素整除,(不是,他们的倍数).

    思路:

    找到他们倍数的个数n就可以了,(正难则反(高中))则答案为 (r-l+1)-n;

    那么,直接变成在 1到 l和1 到 r的个数,再相减,就是最后答案了。

    额,如何找1  到 L 的个数呢?

    L/a就等于a在1到L的倍数的个数了

    那么怎么找既是a又是b的倍数呢?直接 L/(a*b);注意:L/(a*b)=>L/a / b;也就是说,可以在不同时刻来除,不影响结果的。

    这样就可以找集合中各个元素的倍数个数n1, 两个元素乘积的倍数n2, 三个......n3,  四个,,,,,n4

    然后用概率论中的概率公式  s=f(a)+f(b)+f(c)+......(-1)^(n-1)(f(n));(随机时间概率公式,我打了大概的样子)

    中间:因为肯定要用到集合所形成的子集的枚举:怎么枚举呢?

    比如:假如有3个元素{a,b,c}那么有八个子集(子集个数公式2^n, 非空子集和真子集公式2^n-1,非空真子集2^n-2):

    {},{a}, {b}, {c},{a,b},{a,c}, {b,c}, {a,b,c};  元素个数为3

    000  {}

    001  {  ,  ,a}

    010  {  ,b,  }

    100  {c,  ,   }

    011  {  ,b  ,a}

    101  ......

    110  ......

    111  {c,  b,  a}

    这样不就可以表示成 0——7, 

    好了,

    代码是怎样,不多说

    f  用来表示(-1)^(n-1)

    1<<n(n是元素个数)表示子集个数,怎样把每个子集表示一遍。

    for (ll i = 1; i < (1 << n); i++)
     {
      temp = m; f = -1;
      for (int j = 0; j < n; j++)
      {
       if ((i >> j) & 1==1)
       {
        temp /= a[j];
        f *= -1;
       }
      }
      res += temp*f;
     }

    总的代码如下:

    #include<iostream>
    #include<stdio.h>
    #define ll long long
    using namespace std;
    ll a[105];
    ll l, r, n;
    ll ans(ll m)
    {
     ll res = 0;
     ll f, temp;
     for (ll i = 1; i < (1 << n); i++)
     {
      temp = m; f = -1;
      for (int j = 0; j < n; j++)
      {
       if ((i >> j) & 1==1)
       {
        temp /= a[j];
        f *= -1;
       }
      }
      res += temp*f;
     }
     return m-res;
    }
    int main()
    {
     scanf("%lld%lld%lld", &l, &r, &n);
     for (int i = 0; i < n; i++)
     scanf("%lld", &a[i]);
     ll res = ans(r) - ans(l-1);
     printf("%lld\n", res);
    }

    专门讲集合子集的博客

    https://blog.csdn.net/yzl20092856/article/details/39995085

    D 题

    这不是我重点的题目:

    注意一下优化就可以了,本质是用到  一个阶乘中有几个5,有多少个5就有多少个0

    代码如下:

    #include<iostream>
    using namespace std;

    long long f(long long n){
     long long sum = 0;
     while (n){
      sum += n / 5;
      n /= 5;
     }
     return sum;
    }
    int main(){
     long long n;
     long long sum = 0;
     cin >> n;
     for (int i = 5; i <= n; i++){
      if (i + 5 <= n){
       sum += 5 * f(i);
       i += 4;
      }
      else{
       sum += f(i)*(n - i + 1);
       i = n;
      }
     }
     cout << sum;
     return 0;
    }

    emmmmm,这道题,有点神,读题。大佬读题都是说小鱼吃大鱼,维护了平衡。我读的是坐一天月子不吃东西。。。反正,都是看代码猜题意:

    也就是,每过2天,有一天不能吃东西

    就是n-n/3;

    代码如下:

    #include<stdio.h>
    #define ll long long
    int main()
    {
     ll n;
     while (scanf("%lld", &n)!=EOF)
     {
      printf("%lld\n", n - n / 3);
     }
    }

     
  • 相关阅读:
    Android 常见adb命令
    下载安装JDK,并且配置java环境变量
    安装黑苹果教程
    创建不死目录、不死文件
    win10下安装centos7双系统
    Hadoop 3.0完全分布式集群搭建方法(CentOS 7+Hadoop 3.2.0)
    Hadoop 2.0完全分布式集群搭建方法(CentOS7+Hadoop 2.7.7)
    启动HBase脚本start-hbase.sh时报Class path contains multiple SLF4J bindings.解决方法
    HQuorumPeer和QuorumPeerMain进程的区别
    Zookeeper集群安装与配置
  • 原文地址:https://www.cnblogs.com/ALINGMAOMAO/p/9362677.html
Copyright © 2011-2022 走看看