2022-03-07每日刷题打卡

2022-03-07每日刷题打卡

Codeforces

Problem - C - Codeforces

You are given an array a1,a2,…,an consisting of integers from 0 to 9. A subarray al,al+1,al+2,…,ar−1,ar is good if the sum of elements of this subarray is equal to the length of this subarray (∑i=lrai=r−l+1).

For example, if a=[1,2,0], then there are 3 good subarrays: a1…1=[1],a2…3=[2,0] and a1…3=[1,2,0].

Calculate the number of good subarrays of the array a.

Input

The first line contains one integer t (1≤t≤1000) — the number of test cases.

The first line of each test case contains one integer n (1≤n≤10^5) — the length of the array a.

The second line of each test case contains a string consisting of n decimal digits, where the ii-th digit is equal to the value of ai.

It is guaranteed that the sum of n over all test cases does not exceed 10^5.

Output

For each test case print one integer — the number of good subarrays of the array a.

Example

input

Copy

3
3
120
5
11011
6
600005

output

Copy

3
6
1

这题就是说,给你一个数组,每个数组代表一个数,如果连续的x个数加起来等于x,这个子数组就是好的,问你有多少个这样的子数组。

通过这题我们可以知道,好数组的判断标准是:r∑i=l a[i] == r-l+1。我们可以将此等式变为r∑i=l (a[i]-1) == 0,(因为r-l+1等于数组长度,而左边是数组的数相加,左边减去右边就相当于数组中每个数都-1了)此时问题就变成了,看有多少个子数组的区间合为0。我们计算前缀和,这样可以快速的得到两个端点间区间和,我们用哈希表记录每个相同前缀和值的数量,如果有n个相同的前缀和,那么就一共有1+2+3+……+n-1个好数组,因为如果两个端点的前缀和相同,说明它们中间这一段的区间和为0。要注意的是,如果前缀和为0的数量有n个,啧是由1+2+3+……+n-1+n个好数组,因为前缀和为0不光是两个端点间区间和为0,它自身的前缀和也是0,也是满足条件的。记录下所有的结果并输出即可。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<map>
#include<unordered_map>
#include<stack>
 
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 200010;
ll f[N], s[N], e[N];
 
 
int main()
{
	int n;
	cin >> n;
	while (n--)
	{
		map<int, int>mymap;
		ll m, res = 0,sum=0;
		string str;
		cin >> m;
		cin >> str;
		vector<int>v(m + 1), s(m + 1);
		for (int i = 1; i <= m; i++)
		{
			v[i] = str[i-1] - '0' -1;
			s[i] = s[i - 1] + v[i];
			if (s[i] == 0)res++;
			res += mymap[s[i]];
			mymap[s[i]]++;
		}
		cout << res << endl;
	}
 
	
	return 0;
}
Problem - A - Codeforces

You are playing a very popular computer game. The next level consists of nn consecutive locations, numbered from 11 to nn, each of them containing either land or water. It is known that the first and last locations contain land, and for completing the level you have to move from the first location to the last. Also, if you become inside a location with water, you will die, so you can only move between locations with land.

You can jump between adjacent locations for free, as well as no more than once jump from any location with land ii to any location with land i+x, spending xx coins (x≥0).

Your task is to spend the minimum possible number of coins to move from the first location to the last one.

Note that this is always possible since both the first and last locations are the land locations.

Input

There are several test cases in the input data. The first line contains a single integer t (1≤t≤100) — the number of test cases. This is followed by the test cases description.

The first line of each test case contains one integer n (2≤n≤100) — the number of locations.

The second line of the test case contains a sequence of integers a1,a2,…,an (0≤ai≤1), where ai=1 means that the ii-th location is the location with land, and ai=0 means that the ii-th location is the location with water. It is guaranteed that a1=1 and an=1.

Output

For each test case print a single integer — the answer to the problem.

Example

input

Copy

3
2
1 1
5
1 0 1 0 1
4
1 0 1 1

output

Copy

0
4
2

Note

In the first test case, it is enough to make one free jump from the first location to the second one, which is also the last one, so the answer is 00.

In the second test case, the only way to move from the first location to the last one is to jump between them, which will cost 44 coins.

In the third test case, you can jump from the first location to the third for 22 coins, and then jump to the fourth location for free, so the answer is 22. It can be shown that this is the optimal way.

这题的意思是说,有一堆陆地,和水地,你要踩着陆地走到结尾,如果遇到水地则可以跳过去,只能跳一次,跳这一次需要花费金币,花费的金币数是你跳过的地块数量,比如你从第一块跳到第四块,那你要付的金币是4-1=3,让你输出花费金币最少的结果。

很简单的贪心,因为我们只能跳一次,且我们必须能够到达末尾,那我们就先正向遍历数组,当遇到0时停下来,记录当前的下标-1:l,再反向遍历数组,遇到0时停下来,记录当前的下标+1:r,那么所需硬币数就是r-l了。要注意的是,如果正向遍历的时候可以一直走到末尾,说明不需要跳,直接输出0即可,不要再反向遍历。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<map>
#include<unordered_map>
#include<stack>

typedef long long ll;
typedef pair<ll, int>PII;
const int MOD = 1e9 + 7;
const int N = 1010;
ll f[N][N], h[N][N];

int main()
{
 
	int m;
	cin >> m;
	while (m--)
	{
		int n;
		cin >> n;
		vector<int>v(n);
		for (int i = 0; i < n; i++)cin >> v[i];
		int res = 0, l = -1, r = -1;
		for (int i = 0; i < n; i++)
		{
			if (v[i] == 0)
			{
				l = i - 1;
				break;
			}
		}
		if (l == -1)
		{
			cout << 0 << endl;
			continue;
		}
		for (int i = n-1; i >= 0; i--)
		{
			if (v[i] == 0)
			{
				r = i + 1;
				break;
			}
		}
		cout << r - l << endl;
	}
	
	return 0;
}
Problem - B - Codeforces

Daniel is watching a football team playing a game during their training session. They want to improve their passing skills during that session.

The game involves n players, making multiple passes towards each other. Unfortunately, since the balls were moving too fast, after the session Daniel is unable to know how many balls were involved during the game. The only thing he knows is the number of passes delivered by each player during all the session.

Find the minimum possible amount of balls that were involved in the game.

Input

There are several test cases in the input data. The first line contains a single integer t (1≤t≤5⋅10^4) — the number of test cases. This is followed by the test cases description.

The first line of each test case contains one integer n (2≤n≤10^5) — the number of players.

The second line of the test case contains a sequence of integers a1,a2,…,an (0≤ai≤10^9), where ai is the number of passes delivered by the ii-th player.

It is guaranteed that the sum of n over all test cases doesn’t exceed 10^5.

Output

For each test case print a single integer — the answer to the problem.

Example

input

Copy

4
4
2 3 3 2
3
1 5 2
2
0 0
4
1000000000 1000000000 1000000000 1000000000

output

Copy

1
2
0
1

Note

In the first test case, with the only ball, the game can go like this:

2→1→3→4→1→2→3→4→2→3→2.

In the second test case, there is no possible way to play the game with only one ball. One possible way to play with two balls:

2→1→2→3→2→1.

2→3→2→1

In the third example, there were no passes, so 00 balls are possible.

意思是说一群球员在互相传球,给你它们传球的次数,问你他们一共用了多少个球,如果一个球被踢出去后没人传回来,那就要用一个新的球。

我们计算传球次数的最大值,传球次数的总和,如果最大值*2<=总和,则说明他们之间是可以互相消化的(只要球都往最大的那个踢就可以),那么只需要一个球,反之则需要多个球,需要 (最大值 *2-总和 )个球。内部尽可能消化,消化完后剩下的就让最大的那个人自己踢。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<map>
#include<unordered_map>
#include<stack>

typedef long long ll;
typedef pair<double, int>PII;
const int MOD = 1e9 + 7;
const int N = 1010;
ll f[N], h[N];


int main()
{
	int m;
	cin >> m;
	while (m--)
	{
		ll sum = 0, max_num = 0;
		int n;
		cin >> n;
		for (int i = 0; i < n; i++)
		{
			ll num;
			cin >> num;
			sum += num;
			max_num = max(max_num, num);
		}
		if (max_num == 0)
		{
			cout << 0 << endl;
		}
		else if (2 * max_num <= sum)
		{
			cout << 1 << endl;
		}
		else
		{
			cout << 2 * max_num - sum << endl;
		}
	}


	return 0;
}
Problem - C - Codeforces

Egor has a table of size n×mn×m, with lines numbered from 11 to nn and columns numbered from 11 to mm. Each cell has a color that can be presented as an integer from 11 to 105105.

Let us denote the cell that lies in the intersection of the r-th row and the cc-th column as (r,c)(r,c). We define the manhattan distance between two cells (r1,c1) and (r2,c2) as the length of a shortest path between them where each consecutive cells in the path must have a common side. The path can go through cells of any color. For example, in the table 3×43×4 the manhattan distance between (1,2) and (3,3)is 33, one of the shortest paths is the following: (1,2)→(2,2)→(2,3)→(3,3).

Egor decided to calculate the sum of manhattan distances between each pair of cells of the same color. Help him to calculate this sum.

Input

The first line contains two integers nn and mm (1≤n≤m, n⋅m≤100000) — number of rows and columns in the table.

Each of next n lines describes a row of the table. The ii-th line contains mm integers ci1,ci2,…,cim (1≤cij≤100000) — colors of cells in the ii-th row.

Output

Print one integer — the the sum of manhattan distances between each pair of cells of the same color.

Examples

input

Copy

2 3
1 2 3
3 2 1

output

Copy

7

这题说的是,给你一个矩阵,矩阵里有不同的数字,计算任意两个相同点之间的距离,把所有的距离加在一起并输出。

这题用暴力写也可以,但n^2的时间复杂度妥妥超时的,要用到点动规的思想来优化,我们把每个相同数字的下标分别存入两个哈希表里,一个x存x下标,一个y存y下标。存完后开始计算距离总和,每次选一个数字,计算它两两点之间的和,计算前要把对应的x数组和y数组排序,然后累加他们点之间的距离,这里动规的思想就是,比如(0,0)到(1,1),它的距离是2,(1,1)到(2,2)的距离是2,那么(2,2)到(1,1)的距离是多少呢?这里我们可以一眼得出是4,但我们要推出他来,首先(2,2)到(0,0)的路径是(2,2)->(1,1)->(0,0),所以(2,2)到(0,0)的距离是(2,2)->(1,1)的距离+(1,1)->(0,0)的距离,(为方便就这么写坐标了)22到11的距离我们现在算出来了是2,而11到00的距离我们先前就算好了,是2,只要把它加到我们现在的距离上,就是22到11的距离与22到00的距离的总和了。所以我们计算两点之间距离时,可以根据之前已经计算好的距离+现在这个点到上一个点的距离。这样逐步累加起来即可。
至于为什么要排序呢,比如
1 1 2
2 1 1
2 2 1这个矩阵来说,2的点有(0,2)(1,0)(2,0)(2,1)按照我们遍历的顺序,存在数组里的顺序也该是这样,但此时我们从(2,1)点走到(0,2)点,如果是按照上一个点(2,0)的顺序来,那距离会是5,但实际上只用4就足够了(21->22->12->02),所以我们应该排个序,把点尽可能的凑在一起

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<map>
#include<unordered_map>
#include<stack>

typedef long long ll;
typedef pair<ll, ll>PII;
const int MOD = 1e9 + 7;
const int N = 1010;
ll f[N][N], h[N][N];

int main() {
	map<ll, vector<ll>>x, y;
	map<ll, int>color;
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= m; j++)
		{
			cin >> h[i][j];
			x[h[i][j]].push_back(i);
			y[h[i][j]].push_back(j);
			color[h[i][j]] = 1;
		}
	}
	ll sum = 0;
	for (auto i : color)
	{
		sort(x[i.first].begin(), x[i.first].end());
		sort(y[i.first].begin(), y[i.first].end());
		int len = x[i.first].size();
		ll ans_x = 0, ans_y = 0;
		for (int j = 1; j < len; j++)
		{
			ans_x += (x[i.first][j] - x[i.first][j - 1]) * (j);

			ans_y += (y[i.first][j] - y[i.first][j - 1]) * (j);

			sum += ans_x;
			sum += ans_y;
		}
	}
	cout << sum << endl;
	return 0;
}

代码源——div2每日一题

摘桃子 - 题目 - Daimayuan Online Judge

桃园里面有 n 个人在摘桃子。现在 n 个人排成一排,从左到右每个人拥有的桃子数是 ai。 桃园里有一个免费获得桃子的规则,如果连续 x 个人的桃子总数除以 k 的余数正好是 x, 那么这 x 个人就可以免费获得桃子,并且每天只有一次免费获得桃子的机会。 请聪明的你算出一共有多少种不同的方案可以使今天有人免费获得桃子。

输入格式

第一行两个数字 n 、k。

接下来一行 n 个整数 a1,a2,…,an。

输出格式

一个数,表示答案。

样例输入
8 4
4 2 4 2 4 2 4 2
样例输出
7
NOTE

七个不同方案分别是: a1,a2 、 a2,a3 、a3,a4 、a4,a5 、 a5,a6 、a6,a7、a7,a8。 注:只要子串有一个边界不同即为不同的方案

数据规模

所有数据保证 1≤n≤2×105,1≤k≤109,1≤ai≤10^9。

这题和上面cf的Problem - C - Codeforces很像,只不过这里是要取余的数结果等于数的个数。但实际上还是一样的解法,我们还是把每个数-1后计算前缀和,然后找区间和为0的个数,不过我们还要对前缀和取模k,并且这里有一点,因为我们的和取模后的结果要等与数的个数,这就说明了我们的区间不能大过k,因为我们的和取模后肯定是小于k的,如果我们选了大于等于k个数相加,那肯定也是不满足条件,所以我们整一个大小为k的滑动窗口,比较这个窗口里的区间和即可。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<map>
#include<unordered_map>
#include<stack>

typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 200010;
ll f[N], s[N], e[N];


int main()
{
	ll n,k;
	cin >> n;
	map<ll, ll>mymap;
	ll m, res = 0, sum = 0, num;
	int l = 0, r = 0;
	cin >> k;
	vector<int>v(n + 1), s(n + 1);
	for (int i = 1; i <= n; i++)
	{
		cin >> num;
		v[i] = num - 1;
		s[i] = s[i - 1] + v[i];
		s[i] %= k;
		if (s[i] == 0)res++;
		r++;
		if (r - l + 1 > k)
		{
			mymap[s[l]]--;
			l++;
		}
		res += mymap[s[i]];
		mymap[s[i]]++;

	}
	cout << res << endl;

	
	return 0;
}
最大和上升子序列 - 题目 - Daimayuan Online Judge

给定一个长度为 nn 的数组 a1,a2,…,an,问其中的和最大的上升子序列。也就是说,我们要找到数组 p1,p2,…,pm,满足 1≤p1<p2<⋯<pm≤n 并且 ap1<ap2<⋯<apm,使得ap1+ap2+⋯+apmap最大。

输入格式

第一行一个数字 n。

接下来一行 n 个整数 a1,a2,…,an。

输出格式

一个数,表示答案。

样例输入
6
3 7 4 2 6 8
样例输出
21
数据规模

所有数据保证 1≤n≤1000,1≤ai≤10^5

用最大上升子序列长度的方法来写就行,先把数都存入一个数组h里,再准备一个动规数组f,f[i]的意思是,以h[i]结尾的上升子序列的最大和为f[i]。注意,这题说的是最大和上升子序列,而不是最大上升子序列的和,也就是说并不是求最长的上升子序列的和,而是在上升子序列里求和最大的结果。但做法其实差不多,每遍历到一个位置我们就回头遍历之间走过的位置,看有没有小于当前元素的,如果有,比较f[i]和f[j]+h[i]的最大值(i是当前元素的下标,j是回头遍历元素的下标),取两者中最大值。同时准备一个变量res,在此过程中维护最大值,最后返回最大值即可。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<set>
#include<string>
#include<map>
#include<unordered_map>
#include<stack>

typedef long long ll;
typedef pair<ll, int>PII;
const int MOD = 1e9 + 7;
const int N = 1010;
ll f[N], h[N];

int main()
{
	map<ll, ll>mymap;
	map<ll, bool>flag;
	int n;
	cin >> n;
	for (int i = 0; i < n; i++)
	{
		cin >> h[i];
		f[i] = h[i];
	}
	ll res = 0;
	for (int i = 0; i < n; i++)
	{
		for (int j = i-1; j >= 0; j--)
		{
			if (h[i] > h[j])
			{
				f[i] = max(f[i], f[j] + h[i]);
			}
		}
		res = max(res, f[i]);
	}

	cout << res << endl;


	return 0;
}

力扣——每日一题

504. 七进制数

给定一个整数 num,将其转化为 7 进制,并以字符串形式输出。

示例 1:

输入: num = 100
输出: "202"

要特殊注意下num=0和num<0的情况

class Solution {
public:
    string convertToBase7(int num) {
        if(num==0)return "0";
        string str;
        bool flag = false;
        if (num < 0)
        {
            num *= -1;
            flag = true;
        }
        while (num)
        {
            str += num % 7 + '0';
            num/=7;
        }
        if(flag)str += '-';
        reverse(str.begin(), str.end());
        return str;
    }
};
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值