你是细菌的爱好者。你想在一个盒子里培养一些细菌。
最初,盒子是空的。每天早上,您可以将任意数量的细菌放入盒子中。而且到第二天早上,盒子里的每个细菌都会分裂成两个细菌。
您希望在某个早上准确地看到盒子中有x个细菌。(当然你也可以在最后的早上,放入一些细菌,使其正好等于x)
请你计算出最少需要放入的细菌数量。
只有一个正整数x(1≤x≤10^9)。
一个正整数表示最少需要放入的细菌数量。
输入:
5
输出:
2
输入:
8
输出:
1
#【样例说明】:
对于第1个样例:可以在第1天早上放入1个细菌,到第3天早上盒子中会有4个细菌,我们可以再添加1个细菌,使其正好为5个细菌。总共放入2个细菌。
对于第2个样例,我们只需在第1天早上放入1个细菌,就会在第4天早上获得8个细菌,所以答案是1。
##【时间限制、数据范围及描述】:
时间:1s 空间:64M
共有10个测试点:
第1个测试点:1≤x≤10;
第2个测试点:1≤x≤10^2;
第3个测试点:1≤x≤10^3;
第4个测试点:1≤x≤10^4;
第5个测试点:1≤x≤10^5;
第6个测试点:1≤x≤10^6;
第7个测试点:1≤x≤10^7;
第8个测试点:1≤x≤10^8;
第9个测试点:1≤x≤10^9;
第10个测试点:1≤x≤10^9;
代码:
#include
using namespace std;
int N, Ans;
int main() {
cin >> N;
for (; N != 0; N /= 2) {
if (N % 2 != 0) Ans++;
}
cout << Ans << '\n';
return 0;
}
第2题 奇怪的球 ball
文景收到了N(1≤N≤4×10^5)个奇怪的球,球摆成一列,每个球的表面都写着一个数字,第i个球的表面数字是a[i](2≤a[i]≤4×10^5)。
文景准备将所有的球从1到N依次放入桶中。桶是圆柱形的,底面是封死的,只能从圆柱形顶端放入。桶比较窄,桶中的球只能全部竖着叠放。
文景在放球的过程中,奇怪的事情发生了,如果桶中有连续x个值为x的球,这些球将会消失。
请你帮助文景计算出,从1到N依次放入每个球后,桶中的球有多少个?
第一行一个正整数N;
第二行N个正整数,从1到N依次表示每个球表面的数字。
输出N行,每行一个整数,第i行表示放完第i个球后桶中球的个数。
输入:
5
3 2 3 2 2
输出:
1
2
3
4
3
输入:
10
2 3 2 3 3 3 2 3 3 2
输出:
1
2
3
4
5
3
2
3
1
0
#【样例说明】:
考虑样例1:
第1个球放入后,桶中球从下至上依次为:3
第2个球放入后,桶中球从下至上依次为:3 2
第3个球放入后,桶中球从下至上依次为:3 2 3
第4个球放入后,桶中球从下至上依次为:3 2 3 2
第5个球放入后,桶中球从下至上依次为:3 2 3
##【时间限制、数据范围及描述】:
时间:1s 空间:256M
对于30%的数据:1≤N≤10^4;2≤a[i]≤100;
对于100%的数据:1≤N≤4×10^5;2≤a[i]≤4×10^5;
代码:
#include
using namespace std;
#define SIZE 400005
struct Stack_Node {
int Cnt;
int Num;
};
struct A_Stack {
Stack_Node NStack[SIZE];
int Top, TopCnt, TopNum;
void Init() {
Top = 1;
TopCnt = 0;
TopNum = -1;
}
void Push(int X) {
if (X != TopNum) {
TopCnt = 1;
TopNum = X;
NStack[Top++] = {TopCnt, X};
} else {
TopCnt++;
NStack[Top++] = {TopCnt, X};
while (TopCnt == TopNum) {
if (Top - TopCnt < 1)
break;
Top = Top - TopCnt;
TopNum = Top > 1 ? NStack[Top - 1].Num : -1;
TopCnt = Top > 1 ? NStack[Top - 1].Cnt : 0;
}
}
}
};
A_Stack Stack;
int N, Input;
int main() {
Stack.Init();
scanf("%d", &N);
for (int i = 1; i <= N; i++) {
scanf("%d", &Input);
Stack.Push(Input);
printf("%d\n", Stack.Top - 1);
}
return 0;
}
文景有一个长度为N的数组a和一个长度为M的数组b,数组元素都是0或1(1≤N,M≤10^6)。考虑构建一个N×M的矩阵C,C中第i行第j列的元素c[i][j]=a[i]×b[j],容易想到C中的元素也是0或1。
文景想知道在C矩阵中有多少个全1的面积为K(1≤K≤10^6)的子矩阵呢?
子矩阵的面积等于子矩阵的行数乘以列数。
第一行包含三个正整数,表示N,M,K,中间用空格隔开。
第二行包含N个整数0或1,中间用空格隔开。
第三行包含M个整数0或1,中间用空格隔开。
一个整数,表示C矩阵中全1的面积为K的子矩阵的个数。
输入:
3 3 2
1 0 1
1 1 1
输出:
4
输入:
3 5 4
1 1 1
1 1 1 1 1
输出:
14
【样例说明】:
考虑样例1,其C矩阵为:
1 1 1
0 0 0
1 1 1
其中全1的面积为2的子矩阵,只能是1×2的子矩阵,容易看出是4个。
考虑样例2,其C矩阵为:
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
其中全1的面积为4的子矩阵,可以是1×4的子矩阵共6个,可以是2×2的子矩阵共8个,子矩阵总共14个。
##【时间限制、数据范围及描述】:
时间:1s 空间:512M
对于30%的数据:1≤N,M≤60;1≤K≤60;
对于70%的数据:1≤N,M≤1000;1≤K≤1000;
对于100%的数据:1≤N,M≤10^6;1≤K≤10^6;
代码:
#include
using namespace std;
#define SIZE 1000005
#define ll long long
ll CntL[SIZE], CntC[SIZE];
ll L, C, S, LList[SIZE], CList[SIZE];
ll NumListL[SIZE], NumListLTop = 1, NumListC[SIZE], NumListCTop = 1;
ll Cnt;
void Len(ll Size, char Arg) {
for (ll i = 1, Val = Size; i <= Size; i++, Val--) {
if (Arg == 'L') CntL[i] += Val;
else if (Arg == 'C') CntC[i] += Val;
}
}
ll Ans = 0;
int main() {
cin >> L >> C >> S;
Cnt = 0;
for (ll i = 1; i <= L; i++) {
cin >> LList[i];
if (LList[i] == 1) Cnt++;
else {
NumListL[NumListLTop++] = Cnt;
Cnt = 0;
}
}
NumListL[NumListLTop++] = Cnt;
Cnt = 0;
for (ll i = 1; i <= C; i++) {
cin >> CList[i];
if (CList[i] == 1) Cnt++;
else {
NumListC[NumListCTop++] = Cnt;
Cnt = 0;
}
}
NumListC[NumListCTop++] = Cnt;
for (ll i = 1; i <= NumListLTop; i++) {
Len(NumListL[i], 'L');
}
for (ll i = 1; i <= NumListCTop; i++) {
Len(NumListC[i], 'C');
}
for (ll i = 1; i <= S; i++) {
if (S % i == 0) {
ll j = S / i;
Ans += (CntL[i] * CntC[j]);
}
}
cout << Ans << '\n';
return 0;
}
第4题 子序列
给定两个(1,2,…,N)的全排列,分别是P=(p[1],p[2],…,p[N])和Q=( q[1],q[2],…,q[N])。
越越将分别从P和Q中提取子序列(可以不连续),两个子序列必须满足以下两个条件:
1、从P和Q中提取的子序列长度相同,设为k。
2、设从P中提取的子序列为A=(a[1],a[2],…,a[k]),设从Q中提取的子序列为B=(b[1],b[2],…,b[k])。对于每一个i(1≤i≤k),b[i]必须是a[i]的倍数。
请你告诉越越可能提取的子序列A和B的最大长度。
第一行一个正整数N(1≤N≤200000),如题意;
第二行1~N的一个排列,每个数用空格隔开,表示P;
第三行1~N的一个排列,每个数用空格隔开,表示Q;
一个整数,表示可能提取的子序列A和B的最大长度。
输入:
4
3 1 4 2
4 2 1 3
输出:
2
输入:
10
4 3 1 10 9 2 8 6 5 7
9 6 5 4 2 3 8 10 1 7
输出:
6
#【样例说明】:
考虑样例1:子序列A=(1 2),B=(4 2)
考虑样例2:子序列A=(3 1 2 8 5 7),B=(9 6 4 8 10 7)
##【时间限制、数据范围及描述】:
时间:1s 空间:512M
对于20%的数据:1≤N≤10;
对于50%的数据:1≤N≤5000;
对于100%的数据:1≤N≤200000
代码:
#include
#include
using namespace std;
int DP[200005], Arr[3][200005], N, Ans;
int Map[200005];
struct Node {
int First, Second;
} Arr2[20 * 200005], Choose[200005];
bool Compare_Function(Node A, Node B) {
if (A.First != B.First) return A.First < B.First;
return A.Second > B.Second;
}
int BinarySearch(const Node arr[], int n, int Find) {
//返回第一个 > Find的元素
int L = 0, R = n + 1;
while (L + 1 < R) {
int M = (L + R) / 2;
if (arr[M].Second < Find) {
L = M;
} else {
R = M;
}
}
return R;
}
int main() {
cin >> N;
for (int i = 1; i <= 2; i++) {
for (int j = 1; j <= N; j++) {
cin >> Arr[i][j];
if (i == 2) Map[Arr[i][j]] = j;
}
}
int Cnt = 0;
for (int i = 1; i <= N; i++) {
for (int j = 1; Arr[1][i] * j <= N; j++) {
Arr2[++Cnt].First = i;
Arr2[Cnt].Second = Map[Arr[1][i] * j];
}
}
sort(Arr2 + 1, Arr2 + 1 + Cnt, Compare_Function);
int Ans = 0;
for (int i = 1; i <= Cnt; i++) {
int R = BinarySearch(Choose, Ans, Arr2[i].Second);
Choose[R] = Arr2[i];
if (R == Ans + 1) Ans++;
}
cout << Ans << '\n';
return 0;
}