第六次全真模拟训练

第1题     培养细菌 bacteria 

你是细菌的爱好者。你想在一个盒子里培养一些细菌。

最初,盒子是空的。每天早上,您可以将任意数量的细菌放入盒子中。而且到第二天早上,盒子里的每个细菌都会分裂成两个细菌。

您希望在某个早上准确地看到盒子中有x个细菌。(当然你也可以在最后的早上,放入一些细菌,使其正好等于x)

请你计算出最少需要放入的细菌数量。

输入格式

只有一个正整数x(1≤x≤10^9)。

输出格式

一个正整数表示最少需要放入的细菌数量。

输入/输出例子1

输入:

5

输出:

2

输入/输出例子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个球后桶中球的个数。

输入/输出例子1

输入:

5

3 2 3 2 2

输出:

1

2

3

4

3

输入/输出例子2

输入:

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;
}

第3题     计数子矩形 

文景有一个长度为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的子矩阵的个数。

输入/输出例子1

输入:

3 3 2

1 0 1

1 1 1

输出:

4

输入/输出例子2

输入:

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的最大长度。

输入/输出例子1

输入:

4

3 1 4 2

4 2 1 3

输出:

2

输入/输出例子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;
}

你可能感兴趣的:(算法)