【官方题解】:https://www.nowcoder.com/discuss/65411?toCommentId=1134823

【题目链接】:https://www.nowcoder.com/test/question/8fd2b461f3874031a29bdf5aac3c8d51?pid=8527168&tid=12942913

1.

妞妞听说Nowcoder Girl女生编程挑战赛要开始了, 但是她没有足够的勇气报名参加, 牛牛为了帮助妞妞,给她准备一台勇气获得机。初始的时候妞妞的勇气值是0, 勇气获得机有两个按钮:

1、N按钮: 如果当期拥有的勇气值为x, 按下之后勇气值将变为2*x+1,

2、G按钮: 如果当前拥有的勇气值为x, 按下之后勇气值将变为2*x+2,

勇气值过高也会膨胀,所以妞妞需要将自己的勇气值恰好变为n, 请你帮助她设计一个勇气获得机的按键方案使妞妞的勇气值恰好变为n。

输入描述:

输入包括一行, 包括一个正整数n(1 <= n <= 10^9), 表示妞妞最后需要的勇气值。

输出描述:

输出一行字符串, 每个字符表示该次妞妞选择按动的按钮,'N'表示该次按动N按钮,'G'表示该次按动G按钮。

输入例子1:

20

输出例子1:

NGNG

【分析】:仔细观察会发现,每一步的按键方案由奇偶性确定,于是分类确定即可; 也可以用用while实现一个递归。
【代码】:
#include <bits/stdc++.h>

using namespace std;

int n;
stack<char> s;
int main() {
cin >> n;
while(n) {
if(n % == ) {
n = (n - ) / ;
s.push('G');
} else {
n = (n - ) / ;
s.push('N');
}
}
while(!s.empty()) {
printf("%c", s.top());
s.pop();
}
printf("\n");
return ;
}

O(logn)/分类讨论

作者:shiqitao
链接:https://www.nowcoder.com/discuss/65424?type=0&order=0&pos=6&page=0
来源:牛客网 #include <iostream>
#include <string>
using namespace std;
int main()
{
int n; cin >> n;
string result = "";
while (n != ) {
result = (n % ? "N" : "G") + result;
n = (n - ) / ;
}
cout << result;
return ;
}

递归


妞妞得到一个(1~n)的排列p, p, p,...,p, 听村里的老人牛牛说如果让这个排列变为:

对于所有的1 <= i <= n, 都满足p ≠ i, 就可以获得Google Girl Hackathon的入场券。
妞妞仅允许的操作是: 交换排列中两个相邻的元素, 并且妞妞允许做这个操作任意次。

但是Google Girl Hackathon就快要开始了, 妞妞希望做最少的操作就使排列满足要求, 妞妞希望你能帮助她。

输入描述:
输入包括两行, 第一行包括一个正整数n(2 <= n <= 10^5), 表示排列的长度和范围。
第二行包括n个正整数p
, p
, p
,...,p
, 即妞妞得到的排列, 保证是一个1~n的排列。

输出描述:

输出一个整数, 表示妞妞需要的操作次数。

输入例子1:
5
1 4 3 5 2 输出例子1:
2
【分析】:如果某个数没有满足错排要求,直接和相邻的位置swap一下,统计次数即可。如果有一个pi=i或一对pi=i并且pi+1=i+1,则需要一次交换。
【代码】:
作者:NotDeep
链接:https://www.nowcoder.com/discuss/65411
来源:牛客网 #include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + ; int a[maxn], n;
int main() {
cin >> n;
for(int i = ; i < n; i++) scanf("%d", &a[i]);
int res = ;
for(int i = ; i < n - ; i++) {
if(a[i] == i + ) {
swap(a[i], a[i + ]);
res++;
}
}
if(a[n - ] == n) res++;
cout << res << endl;
return ;
}

数论、错排

作者:shiqitao
链接:https://www.nowcoder.com/discuss/65424?type=0&order=0&pos=6&page=0
来源:牛客网 #include <iostream>
using namespace std;
int main()
{
int n; cin >> n;
int equal = , count = , data;
while (count < n) {
cin >> data;
if (data == ++count) {
if (count != n) cin >> data;
count++; equal++;
}
}
cout << equal;
return ;
}

Code2


妞妞参加完Google Girl Hackathon之后,打车回到了牛家庄。

妞妞需要支付给出租车司机车费s元。妞妞身上一共有n个硬币,第i个硬币价值为p[i]元。

妞妞想选择尽量多的硬币,使其总价值足以支付s元车费(即大于等于s)。

但是如果从妞妞支付的这些硬币中移除一个或者多个硬币,剩下的硬币总价值还是足以支付车费的话,出租车司机是不会接受的。例如: 妞妞使用价值为2,5,7的硬币去支付s=11的车费,出租车司机是不会接受的,因为价值为2这个硬币是可以移除的。

妞妞希望能选取最大数量的硬币,使其总价值足以支付车费并且出租车司机能接受。

妞妞希望你能帮她计算最多可以支付多少个硬币。

输入描述:

输入包括两行, 第一行包括两个正整数n和s(1 <= n <= 10, 1 <= s <= 1000), 表示妞妞的硬币个数和需要支付的车费。
第二行包括n个正整数p[i] (1 <= p[i] <= 100),表示第i个硬币的价值。
保证妞妞的n个硬币价值总和是大于等于s。

输出描述:

输出一个整数, 表示妞妞最多可以支付的硬币个数。

输入例子1:

5 9
4 1 3 5 4

输出例子1:

3
【分析】:最多只有10个硬币,简单遍历一下就可以啦。注意到n很小,直接枚举子集判断是否合法,在所有合法的方案中找size最大。
【代码】:
作者:shiqitao
链接:https://www.nowcoder.com/discuss/65424?type=0&order=0&pos=6&page=0
来源:牛客网 #include <iostream>
#include <cmath>
using namespace std;
int main()
{
int n, s; cin >> n >> s;
int data[] = { };
for (int i = ; i < n; i++) {
cin >> data[i];
}
int result = ;
for (int i = ; i < pow(, n); i++) {
int mincoin = , sum = , sumcoin = ;
int temp = i;
for (int j = ; j < n; j++) {
if (temp % ) {
sum += data[j];
mincoin = mincoin < data[j] ? mincoin : data[j];
sumcoin++;
}
temp >>= ;
}
result = sum >= s && sum - mincoin < s ? result>sumcoin ? result : sumcoin : result;
}
cout << result;
return ;
}

简单遍历一下

作者:NotDeep
链接:https://www.nowcoder.com/discuss/65411
来源:牛客网 #include <bits/stdc++.h> using namespace std; int n, s, p[];
int main() {
scanf("%d%d", &n, &s);
for(int i = ; i < n; i++) scanf("%d", &p[i]);
int ans = ;
for (int x = ; x < ( << n); x++) {
int mi = ;
int sum = ;
int cnt = ;
for (int i = ; i < n; i++) {
if ((x & ( << i)) != ) {
mi = min(mi, p[i]);
sum += p[i];
cnt++;
}
}
if (sum >= s && sum - mi < s) {
ans = max(ans, cnt);
}
}
cout << ans << endl; }

O(2^n)


美丽的牛家庄受到了外星人的侵略, 勇敢的妞妞要上战场抵御侵略。

在妞妞上战场前, 村长牛牛给了妞妞N件装备, 妞妞需要选择其中的K件,装备在身上提升自己的战斗力。每件装备有5种属性增幅值,对于第i件装备它的属性增幅值为(r, r, r, r, r), 分别代表该装备对不同的属性值增幅。

当妞妞装备多件装备的时候,由于装备之前会互相影响, 对于每种属性值的增幅并不是所有装备该属性值之和, 而是该种属性值下所有装备中最大的属性值。而妞妞最终增加的战斗力为这5种属性值增幅之和。

妞妞一定要保卫牛家庄, 所以她希望她能提升尽可能多的战斗力, 请你帮帮她计算她最多能增加多少战斗力。

输入描述:

输入包括N+1行,

第一行包括两个正整数N和K(1 <= N <= 10000, 1 <= K <= N), 分别表示一共有的装备数量和妞妞需要选择的装备数量。

接下来的N行,每行5个整数r, r, r, r, r(0 <= r, r, r, r, r <= 10000)表示第i件装备的5种属性值增幅。

输出描述:

输出一个整数,表示妞妞最多能增加的战斗力。

输入例子1:

4 2
30 30 30 30 0
50 0 0 0 0
0 50 0 50 10
0 0 50 0 20

输出例子1:

170

例子说明1:

妞妞要从4件装备中选取2件, 如果妞妞选择第1件和第3件装备,那么增加的战斗力为30 + 50 + 30 + 50 + 10 = 170, 这是最大的方案。

【分析】:没有想到好办法,m大于等于5时取各个属性的最大值,m小于等于3时遍历,m等于4时为防止超时,用一点小小的技巧即可通过。
当k >= 5的时,每一维属性都取最大求和即可。
对于k < 5的时,预处理31种情况可能得到的最大的和。然后dfs枚举子集维护最大的答案即可。
【代码】:
作者:shiqitao
链接:https://www.nowcoder.com/discuss/65424?type=0&order=0&pos=6&page=0
来源:牛客网 #include <iostream>
#include <algorithm>
using namespace std;
int main()
{
int n, m; cin >> n >> m;
int **r = new int*[n], result = ;
int maxr[] = { };
for (int i = ; i < n; i++) {
r[i] = new int[];
for (int j = ; j < ; j++) {
cin >> r[i][j];
maxr[j] = max(maxr[j], r[i][j]);
}
}
if (m == ) {
for (int i = ; i < n; i++) {
int temp = ;
for (int k = ; k < ; k++) {
temp += r[i][k];
}
result = max(result, temp);
}
}
else if (m == ) {
for (int i = ; i < n; i++) {
for (int j = ; j < n; j++) {
int temp = ;
for (int k = ; k < ; k++) {
temp += max(r[i][k], r[j][k]);
}
result = max(result, temp);
}
}
}
else if (m == ) {
for (int i = ; i < n; i++) {
for (int j = ; j < n; j++) {
for (int p = ; p < n; p++) {
int temp = ;
for (int k = ; k < ; k++) {
temp += max(max(r[i][k], r[j][k]), r[p][k]);
}
result = max(result, temp);
}
}
}
}
else if (m == ) {
int maxtemp[][] = { };
for (int p = ; p < ; p++) {
for (int q = p + ; q < ; q++) {
int temp = ;
for (int i = ; i < n; i++) {
temp = max(temp, r[i][p] + r[i][q]);
}
for (int k = ; k < ; k++) {
if (k != p && k != q) {
temp += maxr[k];
}
}
result = max(result, temp);
}
}
}
else {
for (int k = ; k < ; k++) {
result += maxr[k];
}
}
cout << result;
return ;
}

冗长

作者:NotDeep
链接:https://www.nowcoder.com/discuss/65411
来源:牛客网 #include <bits/stdc++.h> using namespace std; const int maxn = 1e4 + ; int mx[];
int num[maxn][];
int N, K;
int sta[];
int dfs(int s, int cur) {
if(cur == K) return ;
int tmp = ;
for(int i = s; i; i = (i - ) & s) tmp = max(tmp, sta[i] + dfs(s ^ i, cur + ));
return tmp;
}
int main() {
scanf("%d%d", &N, &K);
memset(sta, , sizeof(sta));
memset(mx, , sizeof(mx));
for(int i = ; i < N; i++) {
for(int j = ; j < ; j++) {
scanf("%d", &num[i][j]);
mx[j] = max(mx[j], num[i][j]);
}
for(int j = ; j < ; j++) {
int res = ;
for(int k = ; k < ; k++) {
if(j & ( << k)) {
res += num[i][k];
}
}
sta[j] = max(sta[j], res);
}
}
if(K >= ) {
int ans = ;
for(int i = ; i < ; i++) ans += mx[i];
printf("%d\n", ans);
} else {
printf("%d\n", dfs(, ));
}
return ;
}

DFS


如果一个整数x是某个整数的平方, 我们就把整数x称为平方数。

妞妞最喜欢的数字就是平方数, 妞妞现在给你一个N, 妞妞希望你能帮助她找出不大于N的最大的平方数。

输入描述:

输入包括一行, 包括一个正整数N(1 <= N <= 10^9), 表示妞妞给的数字N。

输出描述:

输出一个整数, 即不大于N的最大的平方数。

输入例子1:

10

输出例子1:

9

【分析】:

#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int n; cin >> n;
cout << (int)sqrt(n)*(int)sqrt(n) << endl;
return ;
} //////////////////////////////
#include <bits/stdc++.h>
using namespace std; int n;
int main() {
cin >> n;
int ans = ;
for(int i = ; i <= sqrt(n); i++) ans = i * i;
printf("%d\n",ans);
return ;
}

妞妞参加了Nowcoder Girl女生编程挑战赛, 但是很遗憾, 她没能得到她最喜欢的黑天鹅水晶项链。

于是妞妞决定自己来制作一条美丽的项链。一条美丽的项链需要满足以下条件:

1、需要使用n种特定的水晶宝珠

2、第i种水晶宝珠的数量不能少于l颗, 也不能多于r颗

3、一条美丽的项链由m颗宝珠组成

妞妞意识到满足条件的项链种数可能会很多, 所以希望你来帮助她计算一共有多少种制作美丽的项链的方案。

输入描述:

输入包括n+1行, 第一行包括两个正整数(1 <= n <= 20, 1 <= m <= 100), 表示水晶宝珠的种数和一条美丽的项链需要的水晶宝珠的数量。

接下来的n行, 每行两个整数l r(0 <= l <= r <= 10), 表示第i种宝珠的数量限制区间。

输出描述:

输出一个整数, 表示满足限定条件的方案数。保证答案在64位整数范围内。

输入例子1:

3 5
0 3
0 3
0 3

输出例子1:

12
【分析】: 首先为了方便,在输入的时候,将 [li,ri] 的区间缩小为 [0,ri-li] 。
使用动态规划,DP[i][j]为用前i+1种珠宝制作数量为j的项链的方案数量。
DP[i][j+k]=DP[i-1][j],其中k属于 [0,ri-li]。 可以通过母函数求解。
比较直接的就直接用背包dp算就行了。
【代码】:
#include <iostream>
#include <cstring>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
int *R = new int[n], temp;
for (int i = ; i < n; i++) {
cin >> temp >> R[i];
R[i] -= temp;
m -= temp;
}
long long int **DP = new long long int*[n];
for (int i = ; i < n; i++) {
DP[i] = new long long int[m + ];
memset(DP[i], , sizeof(long long int)*(m + ));
}
for (int i = ; i <= R[]; i++) {
DP[][i] = ;
}
for (int i = ; i < n; i++) {
for (int j = ; j <= R[i]; j++) {
for (int k = ; k <= m - j; k++) {
DP[i][k + j] += DP[i - ][k];
}
}
}
cout << DP[n - ][m] << endl;
delete[] R;
for (int i = ; i < n; i++) {
delete[] DP[i];
}
delete[] DP;
return ;
}

DP

作者:NotDeep
链接:https://www.nowcoder.com/discuss/65411
来源:牛客网 #include <bits/stdc++.h>
using namespace std; long long f[][]; int main() {
int n, m;
scanf("%d%d", &n, &m);
memset(f, , sizeof(f));
f[][] = ;
for (int i = ; i <= n; i++) {
memset(f[i & ], , sizeof(f[i & ]));
int l, r;
scanf("%d%d", &l, &r);
for (int k = l; k <= r; k++)
for (int j = m; j >= k; j--)
f[i & ][j] += f[i + & ][j - k];
}
printf("%lld\n", f[n & ][m]);
return ;
}

母函数

05-11 21:47