2022-04-10每日刷题打卡

2022-04-10每日刷题打卡&&萌新写的十三届蓝桥杯

代码源——每日一题

三回文序列 - 题目 - Daimayuan Online Judge

给定一个长度为n的序列a。

我们定义三回文序列是形如a…a b…b a…a的序列,例如:[1,1,1,2,2,1,1,1]是一个三回文序列,而[1,1,1,2,2,2,3,3,3],[1,1,2,2,1]都不是三回文序列。

现在,希望你找到序列a中最长的三回文序列的长度。

注意,k1,k2可以为0

输入格式

第一行给出一个数字T,表示T组测试用例

对于每一个测试用例

第一行给出序列的长度n

第二行给出序列a1,a2,a3…an

输出格式

对于每一个测试用例,输出最长的三回文序列的长度。

数据范围

1≤t≤2000

1≤∑n≤2e5,1≤ai≤26

样例输入
6
8
1 1 2 2 3 2 1 1
3
1 3 3
4
1 10 10 1
1
26
2
2 1
3
1 1 1
样例输出
7
2
4
1
1
3

先遍历一遍数组,记录每个元素的出现次数,然后枚举所有的数作为a(三回文是一种aba形式的字符串),每次枚举把两边的a的个数都算出来,再枚举中间的b的个数,取总和最大值。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")

#define endl '\n';
typedef long long ll;
typedef pair<int, int> PII;

int n;

int change(vector<int>v, int ans, vector<int>nums)
{
    int l = 0, r = n - 1, cnt = 0, res = nums[ans];
    while (l < r)
    {
        while (l < r && v[l] != ans)
        {
            nums[v[l]]--;
            l++;
        }
        while (l < r && v[r] != ans)
        {
            nums[v[r]]--;
            r--;
        }
        cnt += min(nums[ans], 2);
        nums[ans] -= 2;
        l++, r--;
        for (int i = 1; i <= 26; i++)res = max(res, cnt + nums[i]);
    }
    return res;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t;
    cin >> t;
    while (t--)
    {
        cin >> n;
        vector<int>v(n),nums(27);
        for (int i = 0; i < n; i++)
        {
            cin >> v[i];
            nums[v[i]]++;
        }
        int res = 0;
        for (int i = 1; i < 27; i++)
        {
            if (nums[i] != 0)
                res = max(res, change(v, i,nums));
        }
        cout << res << endl;
    }
    return 0;
}

蓝桥杯——十三届C++B组

(写给萌新的,如果是大佬想看压轴题就请去找大佬的题解罢,说明白点就是我不会呜呜呜)

试题 C: 刷题统计
【问题描述】

小明决定从下周一开始努力刷题准备蓝桥杯竞赛。他计划周一至周五每天做 a 道题目,周六和周日每天做 b 道题目。请你帮小明计算,按照计划他将在第几天实现做题数大于等于 n 题?

【输入格式】

输入一行包含三个整数 a, bn.

【输出格式】

输出一个整数代表天数。

【样例输入】

10 20 99

【样例输出】

8

【评测用例规模与约定】

对于 50% 的评测用例,1 ≤ a, b, n ≤ 10^6.

对于 100% 的评测用例,1 ≤ a, b, n ≤ 10^18

先对n取模(5*a+2 *b),这里一次性算完多少周,然后在循环一周,看看在哪一天刷题量达到n

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
int main()
{
	ll n, a, b;
	cin >> a >> b >> n;
	ll res = n / (a * 5 + b * 2) * 7;
	n %= (a * 5 + b * 2);
	ll v[] = { a,a,a,a,a,b,b };
	if (n <= 0)
	{
		cout << res;
	}
	else
	{
		for (int i = 0; i < 7; i++)
		{
			n -= v[i];
			res++;
			if (n <= 0)
			{
				break;
			}
		}
		cout << res;
	}
	return 0;
}
试题 D: 修剪灌木
【问题描述】

爱丽丝要完成一项修剪灌木的工作。

N 棵灌木整齐的从左到右排成一排。爱丽丝在每天傍晚会修剪一棵灌木,让灌木的高度变为 0 厘米。爱丽丝修剪灌木的顺序是从最左侧的灌木开始,每天向右修剪一棵灌木。当修剪了最右侧的灌木后,她会调转方向,下一天开始向左修剪灌木。直到修剪了最左的灌木后再次调转方向。然后如此循环往复。灌木每天从早上到傍晚会长高 1 厘米,而其余时间不会长高。在第一天的早晨,所有灌木的高度都是 0 厘米。爱丽丝想知道每棵灌木最高长到多高。

【输入格式】

一个正整数 N ,含义如题面所述。

【输出格式】

输出 N 行,每行一个整数,第行表示从左到右第 i 棵树最高能长到多高。

【样例输入】

3

【样例输出】

4

2

4

【评测用例规模与约定】

对于 30% 的数据,N ≤ 10.

对于 100% 的数据,1 < N ≤ 10000.

可以看出,每个灌木能生长的最大高度,就是爱丽丝从自己这里离开的那一天到下一次到这里时所能长到的高度。那么就有两个方向了,一个是爱丽丝从离开自己后向左走,或是离开自己后向右走,我们要看往哪个方向走可以最大延长下一次爱丽丝到达自己的时间。

写成代码就是当前灌木的位置,到达最左边或最右边的距离*2,这就是它能长到的最大高度。

但有点特殊情况,灌木是白天就可以长1m,爱丽丝是晚上割了灌木,所以如果N=1,那么灌木最多可以长到1m,而不是0.(不过数据最小也是大于1,所以不理也可以)

#include<iostream>
using namespace std;
#include<vector>
int main()
{
	int n;
	cin >> n;
	if (n == 1)
	{
		cout << 1;
		return 0;
	}
	vector<int>v;
	for (int i = 1; i <= n; i++)
	{
		v.push_back(max((n - i) * 2, (i - 1) * 2));
	}
	int len = v.size();
	for (int i = 0; i < len; i++)
	{
		cout << v[i];
		if (i != len - 1)cout << endl;
	}
	return 0;
}
试题 E: X 进制减法
【问题描述】

进制规定了数字在数位上逢几进一。X 进制是一种很神奇的进制,因为其每一数位的进制并不固定!例如说某种 X 进制数,最低数位为二进制,第二数位为十进制,第三数位为八进制,则X* 进制数 321 转换为十进制数为 65。现在有两个 X 进制表示的整数 AB,但是其具体每一数位的进制还不确定,只知道 AB 是同一进制规则,且每一数位最高为 N 进制,最低为二进制。请你算出 AB 的结果最小可能是多少。请注意,你需要保证 ABX 进制下都是合法的,即每一数位上的数字要小于其进制。

【输入格式】

第一行一个正整数 N,含义如题面所述。

第二行一个正整数 Ma ,表示 X 进制数 A 的位数。

第三行 Ma个用空格分开的整数,表示 X 进制数 A 按从高位到低位顺序各

个数位上的数字在十进制下的表示。

第四行一个正整数 Mb,表示 X 进制数 B 的位数。

第五行 Mb 个用空格分开的整数,表示 X 进制数 B 按从高位到低位顺序各

个数位上的数字在十进制下的表示。

请注意,输入中的所有数字都是十进制的。

【输出格式】

输出一行一个整数,表示 X 进制数 AB 的结果的最小可能值转换为十进制后再模 1000000007 的结果

【样例输入】

11

3

10 4 0

3

1 2 0

【样例输出】

94

【样例说明】

当进制为:最低位 2 进制,第二数位 5 进制,第三数位 11 进制时,减法

得到的差最小。此时 A 在十进制下是 108,B 在十进制下是 14,差值是 94。

【评测用例规模与约定】

对于 30% 的数据,N ≤ 10; M**a, M**b ≤ 8.

对于 100% 的数据,2 ≤ N ≤ 1000; 1 ≤ M**a, M**b ≤ 100000; AB

这题和一般的进制有区别,假设abc是一个8进制数,那么转化成十进制应该是a*8^2+b *8+c。但这里并不是这样的。

这题突破点在那句“进制规定了数字在数位上逢几进一”上,其实就是说,我们当前位的数,是由上一位的数的进制来决定的,拿题目里的321变成十进制65来说,最高位的3,是通过上一位进了三位得到了,而上一位的进制是10,也就是说,上一位的数满足了3次十进制,即上一位原本的数应该是3*10+2,但是10进制让他进了3位,最后剩下2。同理可推最低位数原本是65,因为这一位的32是上一位的二进制进了32次得到的,即32 *2=64,加上进位后得到的一个1就是65。

此时也可以知道了如何把一个x进制的数变成10进制数,就是重复当前位数乘上上一位的进制+上一位的数,直到最低位为止。

至于X进制的各位进制,则是a和b中各位上最大数+1(因为我们进制只要足够小,最后的结果肯定也小,同时不能让数小于等于进制,不然它们应该会进1,所以进制是最大数+1)

要注意的是,在转成10进制过程中,要始终保持A大于B,比如A是1e9+8,B是2,那么A取模后会变成1,比B要小,那么此时我们应该选择不取模

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
int main()
{
	ll N, n, m;
	cin >> N;
	cin >> n;
	vector<ll>a(n);
	for (int i = n-1; i>=0; i--)
	{
		cin >> a[i];
	}
	cin >> m;
	vector<ll>b(m);
	for (int i = m-1; i >=0; i--)
		cin >> b[i];
	while (n < m)
	{
		a.push_back(0);
		n++;
	}
	while (m < n)
	{
		b.push_back(0);
		m++;
	}
	vector<ll>jz(n+1);
	for (int i = 0; i < n; i++)
	{
		jz[i+1] = max(a[i], b[i]) + 1;
		if (jz[i+1] == 1)jz[i+1] = 2;
	}
	reverse(a.begin(), a.end());
	reverse(b.begin(), b.end());
	ll A = 0, B = 0;
	jz[0] = 1;
	for (int i = 0; i < n; i++)
	{
		B = (B + b[i]) % MOD;
		B = ((jz[n - i - 1] % MOD) * (B % MOD)) % MOD;
	}
	for (int i = 0; i < n; i++)
	{
		A = (A + a[i]);
		
		A = (A * (jz[n - i - 1]))%MOD;
		A += MOD;
	}
	
	cout << (A - B)%MOD;
	return 0;
}
试题 F: 统计子矩阵
【问题描述】

给定一个 N × M 的矩阵 A,请你统计有多少个子矩阵 (最小 1 × 1,最大N × M) 满足子矩阵中所有数的和不超过给定的整数 K?

【输入格式】

第一行包含三个整数 N, MK.之后 N 行每行包含 M 个整数,代表矩阵 A.

【输出格式】

一个整数代表答案。

【样例输入】

3 4 10

1 2 3 4

5 6 7 8

9 10 11 12

【样例输出】

19

【样例说明】

满足条件的子矩阵一共有 19,包含:

大小为 1 × 1 的有 10 个。

大小为 1 × 2 的有 3 个。

大小为 1 × 3 的有 2 个。

大小为 1 × 4 的有 1 个。

大小为 2 × 1 的有 3 个。

【评测用例规模与约定】

对于 30% 的数据,N, M ≤ 20.

对于 70% 的数据,N, M ≤ 100.

对于 100% 的数据,1 ≤ N, M ≤ 500; 0 ≤ A**i j ≤ 1000; 1 ≤ K ≤ 250000000.

暴力只过了70%。

区间前缀和+枚举矩阵大小

#include<iostream>
using namespace std;
#include<vector>
typedef long long ll;
int main()
{
	ll n, m, k;
	cin >> n >> m >> k;
	vector<vector<ll>>v(n + 1, vector<ll>(m + 1));
	vector<vector<ll>>sum(n + 1, vector<ll>(m + 1));
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			cin >> v[i][j];
		}
	}
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + v[i][j];
		}
	}
	int res = 0;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < m; j++)
		{
			for (int l = 1; l <= n - i; l++)
			{
				for (int r = 1; r <= m - j; r++)
				{
					int x1 = l, x2 = l + i, y1 = r, y2 = r + j;
					ll ans = sum[x2][y2] - sum[x2][y1 - 1] - sum[x1 - 1][y2] + sum[x1 - 1][y1 - 1];
					if (ans <= k)
					{
						res++;
					}
				}
			}
		}
	}
	cout << res << endl;
	return 0;
}
试题 I: 李白打酒加强版
【问题描述】

话说大诗人李白,一生好饮。幸好他从不开车。

一天,他提着酒壶,从家里出来,酒壶中有酒 2 斗。他边走边唱:

无事街上走,提壶去打酒。

逢店加一倍,遇花喝一斗。

这一路上,他一共遇到店 N 次,遇到花 M 次。已知最后一次遇到的是花,他正好把酒喝光了。请你计算李白这一路遇到店和花的顺序,有多少种不同的可能?

注意:壶里没酒 ( 0 斗) 时遇店是合法的,加倍后还是没酒;但是没酒时遇花是不合法的。

【输入格式】

第一行包含两个整数 NM.

【输出格式】

输出一个整数表示答案。由于答案可能很大,输出模 1000000007 的结果。

【样例输入】

5 10

【样例输出】

14

【样例说明】

如果我们用 0 代表遇到花,1 代表遇到店,14 种顺序如下:

010101101000000

010110010010000

011000110010000

100010110010000

011001000110000

100011000110000

100100010110000

010110100000100

011001001000100

100011001000100

100100011000100

011010000010100

100100100010100

101000001010100

【评测用例规模与约定】

对于 40% 的评测用例:1 ≤ N, M ≤ 10。

对于 100% 的评测用例:1 ≤ N, M ≤ 100。

暴力bfs只过了40%

我们逆着来,就是李白从末尾出发,每遇到一朵花就往酒壶里填一斗酒,每遇到一个店家倒掉酒壶里一半的酒,问最后壶里还剩9斗酒的可能有多少种。

要注意的是因为正常顺序,李白结尾必定遇到一朵花,所以我们应该以花为起点bfs。而且因为正着来会让酒翻倍,翻倍后酒必然是偶数,所以我们反着来的情况下,只有酒壶里的酒是偶数我们才能遇到店家。

#include<iostream>
using namespace std;
int N, M, res = 0;
const int MOD = 1e9 + 7;
void dfs(int u, int ans,int n,int m)
{
	if (n==0&&m==0)
	{
		if (ans == 2)
		{
			res++;
			res %= MOD;
		}
		return;
	}
	if (n != 0&&ans%2==0)
	{
		dfs(u + 1, ans / 2, n - 1, m);
	}
	if (m != 0)
	{
		dfs(u + 1, ans + 1, n, m - 1);
	}
}

int main()
{
	cin >> N >> M;
	dfs(0, 1, N, M - 1);
	cout << res;
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值