牛客网模拟考试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

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

转载于:https://www.cnblogs.com/y119777/p/6519548.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值