• 牛客网模拟考试3道题


    官方题解。

    https://www.nowcoder.com/discuss/21599

    1. 超级素数幂

    如果一个数字能表示为p^q(^表示幂运算)且p为一个素数,q为大于1的正整数就称这个数叫做超级素数幂。现在给出一个正整数n,如果n是一个超级素数幂需要找出对应的p,q。

    分析:看完题目,p要求是素数,q是大于1的整数,如果暴力枚举素数的话,由于 输入一个正整数n(2 ≤ n ≤ 10^18), 这个数很大,无法枚举所有小于它的素数,复杂度太高,所以只能从q入手,考虑2^64 > 10^18,q的范围只能是2到64,这个范围很小,然后求解,但是确定q以后怎么求解,这就需要开q次方,使用pow,得到结果,然后检查,是否q次幂后相等,是否是素数,返回结果。

    有2道题目的套路跟这道题目差不多:

    https://code.google.com/codejam/contest/5264487/dashboard#s=p1

    https://leetcode.com/problems/smallest-good-base/

    想到开幂次的方法,理解后很容易做出来。

     1 /*
     2 ID: y1197771
     3 PROG: test
     4 LANG: C++
     5 */
     6 #include<bits/stdc++.h>
     7 #define pb push_back
     8 #define FOR(i, n) for (int i = 0; i < (int)n; ++i)
     9 #define dbg(x) cout << #x << " at line " << __LINE__ << " is: " << x << endl
    10 typedef long long ll;
    11 using namespace std;
    12 typedef pair<int, int> pii;
    13 const int maxn = 1e3 + 10;
    14 
    15 ll f(ll x, ll p) {
    16     ll r = 1;
    17     while(p--) {
    18         r *= x;
    19     }
    20     return r;
    21 }
    22 bool check(ll x) {
    23     for (ll i = 2; i * i <= x; i++) {
    24         if(x % i == 0) return 0;
    25     }
    26     return 1;
    27 }
    28 void solve() {
    29     ll x;
    30     cin >> x;
    31     //cout << x << endl;
    32     for (int i = 2; i <= 64; i++) {
    33         ll d = floor(pow(x, 1.0 / i));
    34         //cout << d <<endl;
    35         if(d < 2) continue;
    36         if(!check(d)) continue;
    37         ll t = f(d, i);
    38         if(t == x) {
    39             cout << d << " " << i << endl;
    40             return;
    41         }
    42 
    43     }
    44     cout << "No" << endl;
    45 
    46 }
    47 int main() {
    48     //freopen("test.in", "r", stdin);
    49     //freopen("test.out", "w", stdout);
    50     ios::sync_with_stdio(0);
    51     cin.tie(0); cout.tie(0);
    52     solve();
    53     return 0;
    54 }
    View Code

    2. 序列和

    链接:https://www.nowcoder.com/questionTerminal/46eb436eb6564a62b9f972160e1699c9
    来源:牛客网

    给出一个正整数N和长度L,找出一段长度大于等于L的连续非负整数,他们的和恰好为N。答案可能有多个,我我们需要找出长度最小的那个。
    例如 N = 18 L = 2:
    5 + 6 + 7 = 18
    3 + 4 + 5 + 6 = 18
    都是满足要求的,但是我们输出更短的 5 6 7

    输入数据包括一行:
    两个正整数N(1 ≤ N ≤ 1000000000),L(2 ≤ L ≤ 100)

    分析:我没有做出来,其实这道题目挺简单的,  一般首先想到前n想和n*(n+1)/2,然后考虑怎么入手。考虑到长度2<=l<=100,然后枚举长度,长度为l的和为l*(l+1)/2+k*l,这里要求k*l能被l整除,k是整数,然后直接输出结果就可以!注意题目数组可以从0开始,所以和就发生变化了,为n*(n-1)/2。 关键点是发现l很小,以及求和的平移效果。

     1 /*
     2 ID: y1197771
     3 PROG: test
     4 LANG: C++
     5 */
     6 #include<bits/stdc++.h>
     7 #define pb push_back
     8 #define FOR(i, n) for (int i = 0; i < (int)n; ++i)
     9 #define dbg(x) cout << #x << " at line " << __LINE__ << " is: " << x << endl
    10 typedef long long ll;
    11 using namespace std;
    12 typedef pair<int, int> pii;
    13 const int maxn = 1e3 + 10;
    14 void out(int x, int y) {
    15     for (int i = 0; i < y; i++)
    16         cout << x + i << " ";
    17     cout << endl;
    18 }
    19 void solve() {
    20     int n, l;
    21     cin >> n >> l;
    22     for (int i = l; i <= 100; i++) {
    23         if(n - i * (i - 1) / 2 >= 0 &&(n - i * (i - 1) / 2) % i == 0) {
    24             int b = (n - i * (i - 1) / 2) / i;
    25        
    26             for (int j = 0; j < i; j++) {
    27                 if(j != 0) cout << " ";
    28                 cout << b + j;
    29             }
    30             cout << endl;
    31             return;
    32         }
    33     }
    34     cout << "No" << endl;
    35 }
    36 int main() {
    37     //freopen("test.in", "r", stdin);
    38     //freopen("test.out", "w", stdout);
    39     ios::sync_with_stdio(0);
    40     cin.tie(0); cout.tie(0);
    41     solve();
    42     return 0;
    43 }
    View Code

    3. 页码统计

    输入包括一个整数n(1 ≤ n ≤ 1,000,000,000)

    牛牛新买了一本算法书,算法书一共有n页,页码从1到n。牛牛于是想了一个算法题目:在这本算法书页码中0~9每个数字分别出现了多少次?

    分析:这个我也没解出来,看完题目,应该是以前见过类似的题目,但是想不起来,看题解,才想到是leetcode上面数1的个数那道题目。

    https://leetcode.com/problems/number-of-digit-one/?tab=Description

    但是,这个可以通过分析的出来,我对这类题目的想法是(这类型的题目挺多的,下面总结一下):首先这个题目统计0-9,每个数字可以简化简化成只考虑1的个数(0比较特殊,需要单独处理一下),然后调用10次就可以了!然后对于单个数字,考虑到1-n,n的长度是有限的,我们可以预处理出小于10的个数,小于100的个数,小于1000的个数。。。这个很容易通过找规律得出来。

    下面考虑具体的数字,比如数342里面1的个数,首先是3,结果包括小于100的个数,该位分别为1,2的个数,接着是考虑十位数字4,也是该位为0,1,2,3的情况,4的情况单独考虑,最后是个位数,最后把所有的结果加起来即可。

    贴一下我写的代码,有点丑:

      1 /*
      2 ID: y1197771
      3 PROG: test
      4 LANG: C++
      5 */
      6 #include<bits/stdc++.h>
      7 #define pb push_back
      8 #define FOR(i, n) for (int i = 0; i < (int)n; ++i)
      9 #define dbg(x) cout << #x << " at line " << __LINE__ << " is: " << x << endl
     10 typedef long long ll;
     11 using namespace std;
     12 typedef pair<int, int> pii;
     13 const int maxn = 1e3 + 10;
     14  
     15 ll f[15], s[15];
     16 ll fz[15], sz[15];
     17 void init() {
     18     f[1] = 1; s[1] = 1;
     19     ll b = 1;
     20     fz[1] = 0;
     21     //cout << 1 << " " << f[1] <<" " << s[1] <<  endl;
     22     for (int i = 2; i <= 12; i++) {
     23         b *= 10;
     24         f[i] = b + 9 * s[i - 1];
     25         s[i] = s[i - 1] + f[i];
     26         fz[i] = 9 * s[i - 1];
     27         sz[i] = sz[i - 1] + fz[i];
     28         //cout << i << " " << f[i] <<" " << s[i] <<  " " << fz[i] <<" " << sz[i] << endl;
     29     }
     30 }
     31 ll tar;
     32 ll res;
     33 ll ppow(ll b, ll n) {
     34     ll r = 1;
     35     while(n > 0) {
     36         r *= b;
     37         n--;
     38     }
     39     return r;
     40 }
     41 void work(int x) {
     42     ll t = tar;
     43     ll b = 1;
     44     int len = 0;
     45     while(t > 0) {
     46         len++;
     47         t /= 10;
     48     }
     49     b = ppow(10, len - 1);
     50     //cout << b << " " << len <<endl;
     51     t = tar;
     52     while(t > 0) {
     53         int d = t / b;
     54         //if(d == 0) continue;
     55         res += s[len - 1];
     56         res += s[len - 1] * (d - 1);
     57         if(d > x) {
     58             res += b;
     59         } else if(d == x) {
     60             res += t % b + 1;
     61         }
     62         t %= b;
     63         b /= 10;
     64         len--;
     65     }
     66     //cout << res << endl;
     67 }
     68 void work() {
     69     ll t = tar;
     70     ll b = 1;
     71     int len = 0;
     72     while(t > 0) {
     73         len++;
     74         t /= 10;
     75     }
     76     b = ppow(10, len - 1);
     77     //cout << b << " " << len <<endl;
     78     t = tar;
     79     int x = 0;
     80     bool f = 1;
     81     while(len > 0) {
     82         int d = t / b;
     83         //if(d == 0) continue;
     84          
     85         if(f) {
     86             res += sz[len - 1];
     87             res += (d - 1) * s[len - 1];
     88             f = 0;
     89         } else {
     90             res += d * s[len - 1];
     91             if(d == 0)
     92             res += t % b + 1;
     93             else res += b;
     94         }
     95         //res += sz[len - 1];
     96         //res += s[len - 1] * (d - 1);
     97         //if(d > x) {
     98         //    res += b;
     99         //} else if(d == x) {
    100         //    res += t % b + 1;
    101         //}
    102         t %= b;
    103         b /= 10;
    104         len--;
    105         //cout << d << " " << res << " " << sz[len] << endl;
    106     }
    107     //cout << res << endl;
    108 }
    109 void solve() {
    110     init();
    111     cin >> tar;
    112     //tar = 100;
    113     work();
    114     cout << res;
    115     //return;
    116     //cout << func(tar) <<endl;
    117     //cout << work();
    118     for (int i = 1; i < 10; i++) {
    119         res = 0;
    120         work(i);
    121         cout << " " << res;
    122     }
    123     cout <<endl;
    124  
    125 }
    126  
    127 int main() {
    128     //freopen("test.in", "r", stdin);
    129     //freopen("test.out", "w", stdout);
    130     ios::sync_with_stdio(0);
    131     cin.tie(0); cout.tie(0);
    132     solve();
    133     return 0;
    134 }
    View Code

    官方题解的代码比较优美:

    考虑可以化简的情况,缩减问题的规模,如349,末尾包括0-9的情况,可以简化为统计34的情况,要乘以10,然后是末尾的统计,发生的次数为34,还包括单独发生的次数。

     1 /*
     2 ID: y1197771
     3 PROG: test
     4 LANG: C++
     5 */
     6 #include<bits/stdc++.h>
     7 #define pb push_back
     8 #define FOR(i, n) for (int i = 0; i < (int)n; ++i)
     9 #define dbg(x) cout << #x << " at line " << __LINE__ << " is: " << x << endl
    10 typedef long long ll;
    11 using namespace std;
    12 typedef pair<int, int> pii;
    13 const int maxn = 1e3 + 10;
    14 
    15 vector<int> work(int x) {
    16     vector<int> res(10, 0);
    17     if(x < 1) return res;
    18     int t = x % 10;
    19     if(t != 9) {
    20         res = work(x - 1);
    21         while(x > 0) {
    22             t = x % 10;
    23             x /= 10;
    24             res[t]++;
    25         }
    26         return res;
    27     }
    28     vector<int> v = work(x / 10);
    29     for (int i = 0; i < 10; i++) {
    30         res[i] = v[i] * 10 + x / 10 + (i > 0);
    31     }
    32     return res;
    33 }
    34 void solve() {
    35     int x;
    36     cin >> x;
    37     vector<int> a = work(x);
    38     for (int i = 0; i < 10; i++) {
    39         if(i != 0) cout << " ";
    40         cout << a[i];
    41     }
    42     cout << endl;
    43 }
    44 int main() {
    45     freopen("test.in", "r", stdin);
    46     //freopen("test.out", "w", stdout);
    47     ios::sync_with_stdio(0);
    48     cin.tie(0); cout.tie(0);
    49     solve();
    50     return 0;
    51 }
    View Code

    这个比较简单,而且容易编写,一般不会出错,上面的找规律就比较麻烦一些。

    下面是一些类似的题目:

    https://leetcode.com/problems/k-th-smallest-in-lexicographical-order/?tab=Description 440. K-th Smallest in Lexicographical Order,这个题目算是比较经典

    https://leetcode.com/problems/nth-digit/?tab=Description

    http://www.cnblogs.com/y119777/p/6222408.html

    http://mp.weixin.qq.com/s/fYdPJJ0whWVKEC3aiaclPQ 这个也挺有意思的

    https://leetcode.com/problems/lexicographical-numbers/?tab=Description

    就是这样吧,还有一些可能有点印象,但是想不起来了,总之就是一个是找规律,一个是缩减问题规模,转化为复杂度比较小的问题进行求解。

  • 相关阅读:
    March 13 2017 Week 11 Monday
    March 12 2017 Week 11 Sunday
    March 11 2017 Week 10 Saturday
    March 10 2017 Week 10 Friday
    Mrach 9 2017 Week 10 Thursday
    March 8 2017 Week 10 Wednesday
    玩转Sketch,不容错过的5大实用插件推荐
    网页设计排版中哪些元素最重要?
    5 个关键点!优化你的 UI 原型设计
    如何制作一个完美的错误提示信息
  • 原文地址:https://www.cnblogs.com/y119777/p/6519548.html
Copyright © 2020-2023  润新知