Section 1 Enumeration (ruler method, prefix sum, difference, etc.), greedy

2020 Niu Ke Algorithm Competition Beginner Class

Section 1 Enumeration (ruler method, prefix sum, difference, etc.), greedy

1.2 Don’t talk nonsense, Tangtang, I’m really not a sign-in topic

topic:

insert image description here

Example 1

enter

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

output

3
The main idea of ​​the topic:

(The title is really rubbish, I don’t even know Chinese grammar)

There are n people, each of whom belongs to group 0 or group 1, and has an ability value b. They stand in a row, and at the i-th second, the i-th person can eliminate all the people who are in front of him and whose ability value is smaller than him. It differs from group of people. Someone's father will operate m times, such as operating c, then after the end of the cth second, b1, b2 ... c will all increase by 1, and find out how many people survived in the end.

Ideas:

Simulation, tricks.

Group people, and then simulate it again. However, when performing the operation of m, instead of adding 1 to the first c people, a variable is used to record how much has been added to the front, and then the subsequent number is subtracted from this value, so that it can be guaranteed The relative size has not changed.

Pit point: m operations may be repeated.

code:
#include<iostream>
#include<cstring>
#include<queue>
#define int long long
using namespace std;
const int N=1e6+7;

int num[2][N];
int d[N];

priority_queue<int,vector<int>,greater<int>>p1;
priority_queue<int,vector<int>,greater<int>>p0;

signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
    
    
		int n,m;
		int add=0;
		cin>>n>>m;
		for(int i=1;i<=n;++i)
		{
    
    
			int a,b;
			cin>>a>>b;
			num[a][i]=b;
		}
		for(int i=1;i<=m;++i)
		{
    
    
			int a;
			cin>>a;
			d[a]+=1;//坑点:有可能重复
		}
		int temp=0;
		for(int i=1;i<=n;++i)
		{
    
    
			if(num[1][i]!=0)
			{
    
    
				p1.push(num[1][i]-add);
				while((!p0.empty())&&p0.top()<num[1][i]-add)
				{
    
    
					p0.pop();
					++temp;
				}
			}
			else
			{
    
    
				p0.push(num[0][i]-add);
				while((!p1.empty())&&p1.top()<num[0][i]-add)
				{
    
    
					p1.pop();
					++temp;
				}
			}
			if(d[i])add+=d[i];
		}
		cout<<n-temp<<endl;
		while(!p0.empty())p0.pop();
		while(!p1.empty())p1.pop();
		memset(d,0,sizeof(d));
		memset(num,0,sizeof(num));
	}
	return 0;
}

1.3 Wonderful split

In the distant house of Mi♂Qi♂Miao♂Miao♂, there are a group of natural numbers. They like to take apart themselves to explore ♂ when they have nothing to do. Now they want to know how many different natural numbers they can be split into at most , so that the value of multiplying these natural numbers is equal to the split number.

Enter a description:

第1行输入一个整数T,代表有T组数据。
第2-T+1行,每行输入一个整数n,代表需要被拆分的数。
数据保证:0<T≤100,0<n≤10^9。

Output description:

输出一共T行,第i行输出一个整数,代表第i行输入的n最多可以被拆分成多少个不同的自然数。

Example 1

enter

3
1
4
12

output

1
2
3

illustrate

1可以被拆分为:1
4可以被拆分为:1*4(1*2*2是不允许的,因为有重复的数)
12可以被拆分为:1*2*6或1*3*4

Example 2

enter

1
114514

output

4

illustrate

114514可以被拆分为:1*2*31*1847
The main idea of ​​the topic:

A positive integer can be calculated by multiplying several different positive integers at most.

Ideas:

Mathematics, enumeration.

When n==1, the answer is 1.

When n!=1, 1*a==a, so 1 must be counted as a length, enumerate 1-sqrt(n) (excluding sqrt(n), because there cannot be the same number, 4 cannot be expressed as 2 *2 ), judge whether it is a divisor of n, if it is, remove it, the answer is +1, and the value of the last n must be >=sqrt(n), so this number has never appeared before, so the final answer is +1.

//I read the wrong question at first, and thought it was asking for the number of solutions, and then I saw that 12 should also be 2*6, 3*4, and there are more than 3.

code:
#include<iostream>
#include<algorithm>
#define int long long
#define endl '\n'
using namespace std;
const int N=1e5+7;
const int INF=0x3f3f3f3f;

signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
    
    
		int a;
		cin>>a;
		int ans=0;
		if(a==1)ans=1;//特判
		for(int i=1;i*i<a;++i)//不能取等
		{
    
    
			if(a%i==0)
			{
    
    
				a/=i;
				++ans;
			}
		}
		if(a>1)++ans;//最后肯定要+1的,if可以不写
		cout<<ans<<endl;
	}
	return 0;
}

1.4 Mathematics test

Today qwb is going to take a math test. There are n questions in this set of test papers. The score qwb can get for each question is ai
. Expecting that the score he can get is as large as possible, he is going to choose two discontinuous intervals of length k, namely
[L, L+1, L+2,..., L+k-1], [R, R +1,R+2,...,R+k-1] (R >= L+k).

Enter a description:
第一行一个整数T(T<=10),代表有T组数据
接下来一行两个整数n,k,(1<=n<=200,000),(1<=k,2k <= n)
接下来一行n个整数a1,a2,...,an,(-100,000<=ai<=100,000)
Output description:
输出一个整数,qwb能获得的最大分数

Example 1

enter

2
6 3
1 1 1 1 1 1
8 2
-1 0 2 -1 -1 2 3 -1

output

6
7
The main idea of ​​the topic:

Select two disjoint intervals of length k such that the sum of the two intervals is the largest, and find the sum.

Ideas:

prefix sum, dp.

Consider the simplest method first, violently enumerate two intervals of length k and sum them up, and take the largest sum. The time complexity of this is O(n^3).

Optimizing the sum part with a prefix sum optimizes to O(n^2).

But this still doesn't work, n is as big as 200,000.

When we enumerate the intervals, we first determine the right endpoint of the left interval, then let the right interval move to the right, and find the maximum value of the part >=i+k on the right. After checking once, the left interval moves one step to the right. Then look for the maximum value on the right in the interval on the right. It can be found that, in fact, there is no need to query again for many small numbers on the right, because it will be updated by the large numbers behind, so you can use an array similar to dp to record >= For the maximum value of the i part, you can query the maximum value on the right in O(1).

Then it can be optimized to O(n)

Pit point:

1. When taking the maximum value, the initial value must be small enough. I used -INF before, but it is not enough. The possible minimum value is -n*a, the order of magnitude is 2 *10^10, and the minimum value should be taken at random is very small, such as -1 e 18.

2. It may be a problem with my own writing method. There is an array written as Max[i+k] below, and the maximum i may be n. That is to say, if the array is only opened to 2 e 5, it may be out of bounds here, but in fact the title I didn't get stuck here, or maybe I thought too much.

code:
#include<iostream>
#include<cstring>
#define int long long
#define endl '\n'
using namespace std;
const int N=3e5+7;
const int INF=0x3f3f3f3f;

int a[N];
int d[N];
int Max[N];

signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
    
    
		//memset(Max,-INF,sizeof(Max));//应该无所谓
		int n,k;
		cin>>n>>k;
		for(int i=1;i<=n;++i)
		{
    
    
			cin>>a[i];
			a[i]+=a[i-1];//前缀和
		}
		int m=0;
		for(int i=k;i<=n;++i)
		{
    
    
			d[m++]=a[i]-a[i-k];//离散
		}
		Max[m-1]=d[m-1];
		for(int i=m-2;i>=0;--i)
		{
    
    
			Max[i]=max(Max[i+1],d[i]);//dp思想,表示>=i部分的最大值,后缀最大值
		}
		int temp=-1e18;//坑点
		for(int i=0;i<m;++i)
		{
    
    
			if(d[i]+Max[i+k]>temp)
			{
    
    
				temp=d[i]+Max[i+k];
			}
		}
		cout<<temp<<endl;
	}
	return 0;
}

1.5 Game of Kings

It coincides with the National Day of country H, and the king invites n ministers to play a game with prizes. First, he asked each minister to write an integer on the left and right hands, and the king himself also wrote an integer on the left and right hands. Then, let the n ministers line up in a row, and the king stands at the front of the line. After queuing up, all the ministers will get some gold coins rewarded by the king. The number of gold coins each minister gets is: the product of the numbers on the left hands of all the people in front of the minister divided by the number on his own right hand, Then round down the result obtained.
The king doesn't want a certain minister to get a lot of rewards, so he wants you to help him rearrange the order of the team so that the minister who gets the most rewards gets as few rewards as possible. Note that the position of the king is always at the forefront of the team.

Enter a description:
第一行包含一个整数 n ,表示大臣的人数。
第二行包含两个整数 a 和 b ,之间用一个空格隔开,分别表示国王左手和右手上的整数。
接下来 n 行,每行包含两个整数 a 和 b ,之间用一个空格隔开,分别表示每个大臣左手和右手上的整数。
Output description:
一个整数,表示重新排列后的队伍中获奖赏最多的大臣所获得的金币数。

Example 1

enter

3 
1 1 
2 3 
7 4 
4 6

output

2

illustrate

按 1 、 2 、 3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 ;
按 1 、 3 、 2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 ;
按 2 、 1 、 3 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 ;
按 2 、 3 、 1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 9 ;
按 3 、 1 、 2 这样排列队伍,获得奖赏最多的大臣所获得金币数为 2 ;
按 3 、 2 、 1 这样排列队伍,获得奖赏最多的大臣所获得金币数为 9 。
因此,奖赏最多的大臣最少获得 2 个金币,答案输出 2 。
Remark:
对于 20%的数据,有 1≤ n≤ 10,0 < a,b < 8 ;
对于 40%的数据,有 1≤ n≤20,0 <a,b<8 ;
对于 60%的数据,有 1≤ n≤100 ;
对于 60%的数据,保证答案不超过 109 ;对于 100%的数据,有 1 ≤ n ≤1,000,0 < a,b < 10000 。
The main idea of ​​the topic:

The gold coins obtained by each person are the number obtained by multiplying the number on the left hand of all the people in front and then dividing it by the number on their right hand. Reorder the n people so that the person with the most gold coins has as few gold coins as possible.

Ideas:

Greedy, sorted, high precision.

This is a classic greedy question.

Assume that the i-th person has Li on the left hand and Ri on the right hand, and person i+1 has Li+1 on the left hand and Ri+1 on the right hand.

1. Person i is in front and person i+1 is behind:

Then the number of gold coins of the i-th person is Π/Ri (Π is the product of the numbers on the left hand of all the people in front of him), and the number of gold coins of the i+1 person is (Π*Li)/Ri+1.

Exchange the positions of i and i+1, then the number of gold coins for i becomes (Π*Li+1)/Ri, and the number of gold coins for i+1 becomes Π/Ri+1.

Assuming that i is in front of i+1, it is the optimal solution. At this time, it is only necessary to ensure that (Π*Li+1)/Ri>=(Π*Li)/Ri+1 (because (Π*Li+1)/ Ri>Π/Ri,(Π*Li)/Ri+1>Π/Ri+1

That is, (Li+1) *(Ri+1)>=Li *Ri.

Pit point:

1. Data range, the maximum value of a is 10000, and the maximum value of n is 10000. When all the values ​​of a are maximized, the product is 10000^10000, so a 40000-bit array is required to store large data, and high precision is required.

2. Although the final conclusion is that (Li+1) *(Ri+1)>=Li *Ri, you must not write an equal sign when sorting, and a segment error will occur. The specific reason may be related to sorting, such as sort can't just write a return true.

code:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define int long long
#define endl '\n'
using namespace std;
const int N=1e5+7;
const int INF=0x3f3f3f3f;

int na[N],nb[N];
int answer[N*2];

//我自己写的垃圾高精度,跑的贼慢
string mul(string a,string b)
{
    
    
	string ans;
	memset(na,'\0',sizeof(na));
	memset(nb,'\0',sizeof(nb));
	na[0]=nb[0]=0;
	memset(answer,'\0',sizeof(answer));
    answer[0]=0;
	int la=a.size(),lb=b.size();
	int lmax=la*lb;
	for(int i=0;i<la;++i)
	{
    
    
		na[la-i-1]=a[i]-'0';//反向
	}
	for(int i=0;i<lb;++i)
	{
    
    
		nb[lb-i-1]=b[i]-'0';//反向
	}
	for(int i=0;i<la;++i)
	{
    
    
		for(int j=0;j<lb;++j)
		{
    
    
			answer[i+j]+=na[i]*nb[j];
		}
	}
	for(int i=0;i<lmax;++i)
	{
    
    
		answer[i+1]+=answer[i]/10;
		answer[i]%=10;
	}
	while(!answer[lmax]&&lmax>0)
		--lmax;
	for(int i=lmax;i>=0;--i)
		ans+=answer[i]+'0';
	return ans;
}

string div(string a,int b)
{
    
    
	string ans;
	memset(na,'\0',sizeof(na));
	memset(nb,'\0',sizeof(nb));
	na[0]=nb[0]=0;
	int la=a.size();
	int lmax=la;
	for(int i=0;i<la;++i)
	{
    
    
		na[la-i-1]=a[i]-'0';//反向
	}
	int yushu=0;
	for(int i=lmax-1;i>=0;--i)
	{
    
    
		nb[i]=(yushu*10+na[i])/b;//答案存到nb里面
		yushu=(yushu*10+na[i])%b;
	}
	while(!nb[lmax-1]&&lmax>1)
		--lmax;
	for(int i=lmax-1;i>=0;--i)
		ans+=nb[i]+'0';
	return ans;
}

bool cmp2(string a,string b)//比较a是否大于等于b
{
    
    
	if(a[0]=='-'&&b[0]!='-')return false;
	if(a[0]!='-'&&b[0]=='-')return true;
    if(a.size()==b.size())return a>=b;
    return a.size()>b.size();
}

struct node
{
    
    
	int a,b;
}d[N];

bool cmp(node a,node b){
    
    return a.a*a.b<b.a*b.b;}
//要用到大数
signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int n;
	cin>>n;
	cin>>d[0].a>>d[0].b;
	for(int i=1;i<=n;++i)
	{
    
    
		cin>>d[i].a>>d[i].b;
	}
	sort(d+1,d+1+n,cmp);
	string ans="-20000";
	string temp=to_string(d[0].a);
	for(int i=1;i<=n;++i)
	{
    
    
		string now=div(temp,d[i].b);
		if(!cmp2(ans,now))
		{
    
    
			ans=now;
		}
		temp=mul(temp,to_string(d[i].a));
	}
	cout<<ans<<endl;
	return 0;
}

1.6 Carpeting

In order to prepare for a unique awards ceremony, the organizers laid out some rectangular carpets in a rectangular area of ​​the venue (which can be regarded as the first quadrant of the plane Cartesian coordinate system). There are n carpets in total, numbered from 1 to n. Now these carpets are laid parallel to the coordinate axis in order of numbering from small to large, and the carpets laid later are covered on the carpets that have been laid before. After the rugs are laid, the organizers want to know the number of the top rug that covers a certain point on the floor. Note: Points on the boundary and four vertices of the rectangular rug are also covered by the rug.

Enter a description:
第一行,一个整数n,表示总共有n张地毯。
接下来的n行中,第i+1行表示编号i的地毯的信息,包含四个正整数a,b,g,k,每两个整数之间用一个空格隔开,分别表示铺设地毯的左下角的坐标(a,b)以及地毯在x轴和y轴方向的长度。
第n+2行包含两个正整数x和y,表示所求的地面的点的坐标(x,y)。
Output description:
输出共1行,一个整数,表示所求的地毯的编号;若此处没有被地毯覆盖则输出-1。

Example 1

enter

3
1 0 2 3
0 2 3 3
2 1 3 3
2 2

output

3

illustrate

如下图,1号地毯用实线表示,2号地毯用虚线表示,3号用双实线表示,覆盖点(2,2)的最上面一张地毯是3号地毯。

img

Remark:
对于30%的数据,有n≤2;
对于50%的数据,有0≤a,b,g,k≤100;
对于100%的数据,有0≤n≤10,000,0≤a,b,g,k≤100,000。
The main idea of ​​the topic:

Put several rectangles that may overlap in a plane Cartesian coordinate system, and ask what is the topmost matrix at a certain position.

Ideas:

Simulate water problems.

Put the rectangles in order to see which is the last rectangle at that point.

code:
#include<iostream>
#include<algorithm>
#define int long long
#define endl '\n'
using namespace std;
const int N=1e4+7;
const int INF=0x3f3f3f3f;

struct node
{
    
    
	int a,b,g,k;
}d[N];

signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int n;
	cin>>n;
	for(int i=0;i<n;++i)
	{
    
    
		cin>>d[i].a>>d[i].b>>d[i].g>>d[i].k;
	}
	int x,y;
	cin>>x>>y;
	int ans=-1;
	for(int i=0;i<n;++i)
	{
    
    
		if(x>=d[i].a&&y>=d[i].b&&x<=d[i].a+d[i].g&&y<=d[i].b+d[i].k)ans=i+1;
	}
	cout<<ans<<endl;
	return 0;
}

1.7 Souvenir grouping

New Year's Day is approaching, and the school students will let Lele be in charge of distributing souvenirs for the New Year's party. In order to make the value of the souvenirs obtained by the students participating in the party relatively balanced, he needs to group the purchased souvenirs according to the price, but each group can only include at most two souvenirs, and the sum of the prices of each group of souvenirs cannot exceed a given an integer of . In order to ensure that all souvenirs are distributed in the shortest possible time, Lele hopes to have the least number of groups.
Your task is to write a program to find the one with the least number of groups among all grouping schemes, and output the least number of groups.

Enter a description:
第 1 行包括一个整数 w,为每组纪念品价格之和的上限。
第 2 行为一个整数n,表示购来的纪念品的总件数。
第 3 ~ n+2 行每行包含一个正整数 pi ( 5 ≤ pi ≤ w ) ,表示所对应纪念品的价格。
Output description:
包含一个整数,即最少的分组数目。

Example 1

enter

100
9
90
20
20
30
50
60
70
80
90

output

6
Remark:
50%的数据满足:1 ≤ n ≤ 15
100%的数据满足:1 ≤ n ≤ 30000, 80 ≤ w ≤ 200
The main idea of ​​the topic:

Take two numbers as a group, and the sum cannot be greater than w, and find the minimum number of groups.

Ideas:

Greedy, sort.

Each time the sum of the largest and the smallest is not greater than w, they can be divided into a group, otherwise let the largest single group, simulate it again, and finally make a separate judgment when l==r.

Prove the correctness of this greediness:

A non-decreasing sequence abcde (a<=b<=c<=d<=e).

1. If a+e<=w, then there must be a+d<=w

2. If a+e<=w, but b+e>w, b+d is better (smaller) than e+d at this time, so it is the optimal strategy to first remove the large number

code:
#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
#define endl '\n'
using namespace std;
const int N=3e4+7;
const int INF=0x3f3f3f3f;

int a[N];

signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int w;
	cin>>w;
	int n;
	cin>>n;
	for(int i=0;i<n;++i)
	{
    
    
		cin>>a[i];
	}
	sort(a,a+n);
	int ans=0;
	int l=0,r=n-1;
	while(l<r)
	{
    
    
		if(a[l]+a[r]<=w)
		{
    
    
			++l;
			--r;
			++ans;
		}
		else
		{
    
    
			--r;
			++ans;
		}
	}
	if(l==r)++ans;
	cout<<ans<<endl;
	return 0;
}

1.8 The tree outside the school gate

There is a row of trees on the road with length L outside the gate of a certain school, and the distance between every two adjacent trees is 1 meter. We can regard the road as a number axis, one end of the road is at the position of 0 on the number axis, and the other end is at the position of L; each integer point on the number axis, namely 0, 1, 2, ..., L, has a tree planted .

Because there are some areas on the road to be used to build subways. These regions are represented by their starting and ending points on the number line. It is known that the coordinates of the start point and end point of any area are integers, and there may be overlapping parts between areas. The trees in these areas (including the two trees at the ends of the areas) are now to be removed. Your task is to calculate how many trees will remain on the road after all these trees are removed.

Enter a description:

第一行有两个整数:L(1 <= L <= 10000)和 M(1 <= M <= 100),L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。接下来的M行每行包含两个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标。

Output description:

包括一行,这一行只包含一个整数,表示马路上剩余的树的数目。

Example 1

enter

500 3
150 300
100 200
470 471

output

298

Remark:

对于20%的数据,区域之间没有重合的部分;
对于其它的数据,区域之间有重合的情况。

The main idea of ​​the topic:

Each time an interval is covered, find the sum of the lengths of the intervals that are not covered

Ideas:

Simulate water problems.

The data is very small, just O(n*m) simulation.

If the data is larger, use the prefix and + difference to determine the final number of positive numbers.

If the data is larger, use the discretization method.

code:

#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
#define endl '\n'
using namespace std;
const int N=1e4+7;
const int INF=0x3f3f3f3f;

bool a[N];

signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int L,M;
	cin>>L>>M;
	for(int i=0;i<M;++i)
	{
    
    
		int l,r;
		cin>>l>>r;
		for(int i=l;i<=r;++i)
		{
    
    
			a[i]=1;
		}
	}
	int ans=0;
	for(int i=0;i<=L;++i)
	{
    
    
		if(!a[i])++ans;
	}
	cout<<ans<<endl;
	return 0;
}

1.9 Obvious random numbers

Mingming wanted to invite some students to do a questionnaire survey at school. For the objectivity of the experiment, he first used a computer to generate N random integers between 1 and 1000 (N ≤ 100). For the repeated numbers, only Keep one and remove the other same numbers. Different numbers correspond to different student numbers. Then sort these numbers from small to large, and go to the classmates to investigate in the order they are arranged. Please help Mingming complete the work of "deduplication" and "sorting".

Enter a description:

输入有2行,第1行为1个正整数,表示所生成的随机数的个数:N
第2行有N个用空格隔开的正整数,为所产生的随机数。

Output description:

输出2行,第1行为1个正整数M,表示不相同的随机数的个数。
第2行为M个用空格隔开的正整数,为从小到大排好序的不相同的随机数。

Example 1

enter

10
20 40 32 67 40 20 89 300 400 15

output

8
15 20 32 40 67 89 300 400

The main idea of ​​the topic:

Sort + deduplicate an array.

Ideas:

hard dry.

code:

#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
const int N=1e5+7;

int a[103];

signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int n;
	cin>>n;
	for(int i=1;i<=n;++i)
	{
    
    
		cin>>a[i];
	}
	sort(a+1,a+n+1);
	int ans=0;
	for(int i=1;i<=n;++i)
	{
    
    
		if(a[i]==a[i-1])continue;
		++ans;
	}
	cout<<ans<<endl;
	for(int i=1;i<=n;++i)
	{
    
    
		if(a[i]==a[i-1])continue;
		cout<<a[i]<<' ';
	}
	return 0;
}

1.10 spelling

Assuming n positive integers (n ≤ 20), connect them in a row to form a largest multi-digit integer.
For example: when n=3, the maximum integer formed by connecting 3 integers 13, 312, 343 is: 34331213 Another example
: when n=4, the maximum integer formed by connecting 4 integers 7, 13, 4, 246 is: 7424613

Enter a description:

第一行,一个正整数n。
第二行,n个正整数。

Output description:

一个正整数,表示最大的整数

Example 1

enter

3
13 312 343

output

34331213

The main idea of ​​the topic:

Given several numbers, find the largest number that is concatenated by the first digits

Ideas:

Greedy + sort.

How to judge which of the two numbers is the best? For example, a and b, just compare the size of ab and ba. If ab>ba, then it is optimal to put a in front. And the exchange of a and b will not affect the arrangement of the numbers in front and behind.

Note: It does not depend on whoever is the most high-ranking person to put it in front, such as 3 31 32, the maximum is 33231.

code:

#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
using namespace std;
const int N=1e5+7;
const int INF=0x3f3f3f3f;
bool cmp(string a,string b)
{
    
    
	return a+b>b+a;
}
string a[23];
signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int n;
	cin>>n;
	for(int i=0;i<n;++i)
	{
    
    
		cin>>a[i];
	}
	sort(a,a+n,cmp);
	for(int i=0;i<n;++i)cout<<a[i];
	return 0;
}

1.11 Laser bombs

A new type of laser bomb that can destroy all targets within a square with side length R.

Now there are n (N ≤ 10000) targets on the map, and the integer Xi, Yi (the value is in [0,5000]) represents the position of the target on the map, and each target has a value.

Laser bombs are released through satellite positioning, but it has a disadvantage, that is, its blasting range, that is, the sides of the square whose side length is R must be parallel to the x and y axes.

If the target is on the side of the explosion square, the target will not be destroyed.

Enter a description:

输入文件的第一行为正整数n和正整数R,接下来的n行每行有3个正整数,分别表示 xi,yi ,vi 。

Output description:

输出文件仅有一个正整数,表示一颗炸弹最多能炸掉地图上总价值为多少的目标(结果不会超过32767)。

Example 1

enter

2 1
0 0 1
1 1 1

output

1

insert image description here

The main idea of ​​the topic:

Find the sum of the numbers inside the largest square with side length r.

Ideas:

Two-dimensional prefix sum.

Violent enumeration of each position, O(n^2).

Note: i+r may be out of bounds.

code:
#include<iostream>
#include<algorithm>
#include<cstring>
//#define int long long
#define endl '\n'
using namespace std;
const int N=5e3+7;
const int INF=0x3f3f3f3f;

int Map[N][N];
int sum[N][N];

signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int n,r;
	cin>>n>>r;
	for(int i=0;i<n;++i)
	{
    
    
		int x,y,v;
		cin>>x>>y>>v;
		Map[x+1][y+1]+=v;
	}
	for(int i=1;i<=5e3+2;++i)
	{
    
    
		for(int j=1;j<=5e3+2;++j)
		{
    
    
			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+Map[i][j];
		}
	}
	int ans=0;
	for(int i=1;i<=5e3+2-r;++i)
	{
    
    
		for(int j=1;j<=5e3+2-r;++j)
		{
    
    
			ans=max(ans,sum[i+r-1][j+r-1]-sum[i+r-1][j-1]-sum[i-1][j+r-1]+sum[i-1][j-1]);
		}
	}
	cout<<ans<<endl;
	return 0;
}

1.12 Value weeks

topic description

There are some students on the road with a length of L in JC, and the distance between every two adjacent students is 1 meter. We can regard the road as a number axis, one end of the road is at the position of 0 on the number axis, and the other end is at the position of L; each integer point on the number axis, that is, 0, 1, 2, ... L, has a value Zhou classmates. Since Shui Baobao has some areas to do things with ssy, in order to avoid such things from leaking, Shui Baobo has to kick away people in some areas. These regions are represented by their starting and ending points on the number line. It is known that the coordinates of the start point and end point of any area are integers, and there may be overlapping parts between areas. The people in these areas (including the two at the ends of the areas) are now to be removed. Your task is to calculate how many people are left on the road after driving all these people away.

Enter a description:
第一行有2个整数L和M,L代表马路的长度,M代表区域的数目,L和M之间用一个空格隔开。 接下来的M行每行包含2个不同的整数,用一个空格隔开,表示一个区域的起始点和终止点的坐标
Output description:
1个整数,表示马路上剩余的人的数目。

Example 1

enter

500 3
150 300
100 200
470 471

output

298

illustrate

对于所有的数据,1≤L≤100000000
对于10%的数据,1<=M<=100
对于20%的数据,1<=M<=1000
对于50%的数据,1<=M<=100000
对于100%的数据,1<=M<=1000000
The main idea of ​​the topic:

Same as 1.8

Ideas:

In fact, it is the data enhanced version of 1.8, using the discretization method.

Although L is very large, the maximum is 100000000, but M is only 1000000, so these intervals can be stored and sorted, and then the discontinuous part can be calculated.

code:
#include<iostream>
#include<algorithm>
#define int long long
#define endl '\n'
using namespace std;
const int N=1e6+7;
const int INF=0x3f3f3f3f;

struct node
{
    
    
	int l,r;
}a[N];

signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int L,M;
	cin>>L>>M;
	for(int i=0;i<M;++i)
	{
    
    
		cin>>a[i].l>>a[i].r;
	}
	sort(a,a+M,[](node a,node b){
    
    if(a.l==b.l)return a.r<b.r;return a.l<b.l;});
	int ans=0;
	int left=-1;
	for(int i=0;i<M;++i)
	{
    
    
		if(a[i].l<=left)
		{
    
    
			left=max(a[i].r,left);
			continue;
		}
		ans+=a[i].l-left-1;
		left=a[i].r;
	}
	ans+=L-left;
	cout<<ans<<endl;
	return 0;
}

1.13 Selfish Grazing

Each of Farmer John’s N (1 <= N <= 50,000) cows likes to graze in a certain part of the pasture, which can be thought of as a large one-dimeensional number line. Cow i’s favorite grazing range starts at location Si and ends at location Ei (1 <= Si < Ei; Si < Ei <= 100,000,000).
Most folks know the cows are quite selfish; no cow wants to share any of its grazing area with another. Thus, two cows i and j can only graze at the same time if either Si >= Ej or Ei <= Sj. FJ would like to know the maximum number of cows that can graze at the same time for a given set of cows and their preferences.

Consider a set of 5 cows with ranges shown below:
  ... 1    2    3    4    5    6    7    8    9   10   11   12   13 ...
  ... |----|----|----|----|----|----|----|----|----|----|----|----|----
Cow 1:      <===:===>          :              :              :
Cow 2: <========:==============:==============:=============>:
Cow 3:          :     <====>   :              :              :
Cow 4:          :              :     <========:===>          :
Cow 5:          :              :     <==>     :              :

These ranges represent (2, 4), (1, 12), (4, 5), (7, 10), and (7, 8), respectively.
For a solution, the first, third, and fourth (or fifth) cows can all graze at the same time. If the second cow grazed, no other cows could graze. Also, the fourth and fifth cows cannot graze together, so it is impossible for four or more cows to graze.
Enter a description:
* Line 1: A single integer: N
* Lines 2..N+1: Line i+1 contains the two space-separated integers: Si and Ei
Output description:
* Line 1: A single integer representing the maximum number of cows that can graze at once.

Example 1

enter

5 
2 4 
1 12 
4 5 
7 10 
7 8 

output

3
The main idea of ​​the topic:

Find the maximum number of non-covered intervals.

Ideas:

greedy. Interval coverage.

Proof: In the range that can be selected, choosing one with an earlier end time is no worse than other schemes. Because the end time is early, there will be more space left behind.

code:
#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
#define endl '\n'
using namespace std;
const int N=5e4+7;
const int INF=0x3f3f3f3f;

struct node
{
    
    
	int l,r;
}a[N];

signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int n;
	cin>>n;
	for(int i=0;i<n;++i)
	{
    
    
		cin>>a[i].l>>a[i].r;
	}
	sort(a,a+n,[](node a,node b){
    
    return a.r<b.r;});
	int right=0;
	int ans=0;
	for(int i=0;i<n;++i)
	{
    
    
		if(a[i].l>=right)
		{
    
    
			right=a[i].r;
			++ans;
		}
	}
	cout<<ans<<endl;
	return 0;
}

1.14 Cut strips

You can draw a vertical line between any two numbers in a row, thus cutting that strip, and possibly other strips. Ask at least how many cuts are needed to cut each strip.

Enter a description:
Line 1: A single integer, N(2 <= N <= 32000)
Lines 2..N+1: Each line contains two space-separated positive integers that describe a leash. The first is the location of the leash's stake; the second is the length of the leash.(1 <= length <= 1e7)
Output description:
Line 1: A single integer that is the minimum number of cuts so that each leash is cut at least once.

Example 1

enter

7
2 4
4 7
3 3
5 3
9 4
1 5
7 3

output

2
The main idea of ​​the topic:

Find the number of sets with overlapping intervals.

Ideas:

greedy.

Sort by the left endpoint, because each interval must be considered, so you can start from the leftmost interval, judge the intervals that overlap with it, and take their smallest right endpoint as the next reference point.

code:
#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
#define endl '\n'
using namespace std;
const int N=5e4+7;
const int INF=0x3f3f3f3f;

pair<int,int>a[N];

signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int n;
	cin>>n;
	for(int i=0;i<n;++i)
	{
    
    
		int c,d;
		cin>>c>>d;
		a[i].first=c;
		a[i].second=c+d;
	}
	sort(a,a+n);
	int right=0;
	int ans=0;
	for(int i=1;i<n;++i)
	{
    
    
		if(right>a[i].first)
		{
    
    
			right=min(right,a[i].second);
		}
		else
		{
    
    
			++ans;
			right=a[i].second;
		}
	}
	cout<<ans<<endl;
	return 0;
}

1.15 "Earth" boulder rolling

Patchouli has mastered a kind of earth attribute magic

She uses this magic to build a large ball of earth and send it all the way down to crash into obstacles

The soil ball has a stability x, if x < 0, it will fall apart immediately

Every time it collides with an obstacle, the soil ball will lose the stability of ai, and after the collision, it will give back the stability of bi from the obstacle

Paqiuli wanted to know, if the order of the obstacles is arranged reasonably, can all the obstacles be destroyed while ensuring that the soil ball does not fall apart?

Enter a description:
输入一个整数T,代表T组数据,每组数据中:
前一行两个整数n , m,表示障碍个数和土球的稳定性
接下来一行两个整数,分别表示障碍的ai和bi
Output description:
若可以,输出“Yes”(不含引号),否则输出“No”(不含引号)

Example 1

enter

1
5 50
49 49
52 0
5 10
26 24
70 70

output

No
Remark:
Σn <= 500000, 1<=m<=100000,0<=a,b<=100000
The main idea of ​​the topic:

The initial value is m, subtract ai and add bi each time, and ask whether the value can be guaranteed not to be negative after sorting.

Ideas:

greedy.

Similar to 1.13

First sort the part of b>=a from small to large, and finally it must be the maximum value of the whole process, and then consider the part of b<a.

This is actually the problem of the previous interval. The value keeps decreasing, corresponding to the number axis from left to right, and the one with the smaller b is in front, and the one with the right end of the selected interval is in front.

code:
#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
#define endl '\n'
using namespace std;
const int N=5e5+7;
const int INF=0x3f3f3f3f;

struct node
{
    
    
	int l,r;
}a[N],b[N];

signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
    
    
		int n,m;
		int numl=0;
		int numr=0;
		cin>>n>>m;
		for(int i=0;i<n;++i)
		{
    
    
			int l,r;
			cin>>l>>r;
			if(l<=r)
			{
    
    
				a[numl].l=l;
				a[numl].r=r;
				++numl;
			}
			else
			{
    
    
				b[numr].l=l;
				b[numr].r=r;
				++numr;
			}
		}
		sort(a,a+numl,[](node c,node d){
    
    return c.l<d.l;});
		sort(b,b+numr,[](node c,node d){
    
    return c.r>d.r;});
		int temp=m;
		bool check=1;
		for(int i=0;i<numl;++i)
		{
    
    
			if(temp-a[i].l<0)
			{
    
    
				check=0;
				break;
			}
			temp+=a[i].r-a[i].l;
		}
		for(int i=0;i<numr;++i)
		{
    
    
			if(temp-b[i].l<0)
			{
    
    
				check=0;
				break;
			}
			temp+=b[i].r-b[i].l;
		}
		if(!check)cout<<"No"<<endl;
		else cout<<"Yes"<<endl;
	}
	return 0;
}

1.16 Flip Game

Flip game is played on a rectangular 4x4 field with two-sided pieces placed on each of its 16 squares. One side of each piece is white and the other one is black and each piece is lying either it’s black or white side up. Each round you flip 3 to 5 pieces, thus changing the color of their upper side from black to white and vice versa. The pieces to be flipped are chosen every round according to the following rules:

  1. Choose any one of the 16 pieces.
  2. Flip the chosen piece and also all adjacent pieces to the left, to the right, to the top, and to the bottom of the chosen piece (if there are any).

imgConsider the following position as an example:

bwbw
wwww
bbwb
bwwb
Here “b” denotes pieces lying their black side up and “w” denotes pieces lying their white side up. If we choose to flip the 1st piece from the 3rd row (this choice is shown at the picture), then the field will become:

bwbw
bwww
wwwb
wwwb
The goal of the game is to flip either all pieces white side up or all pieces black side up. You are to write a program that will search for the minimum number of rounds needed to achieve this goal.

Enter a description:
  The input consists of 4 lines with 4 characters "w" or "b" each that denote game field position. 
Output description:
  Write to the output file a single integer number - the minimum number of rounds needed to achieve the goal of the game from the given position. If the goal is initially achieved, then write 0. If it's impossible to achieve the goal, then write the word "Impossible" (without quotes). 

Example 1

enter

bwwb
bbwb
bwwb
bwww

output

4
The main idea of ​​the topic:

There are white and black on a 4*4 grid. After operating on a grid, the grid and the upper, lower, left, and right grids can be changed in color. Ask the minimum number of steps to make all the grids black or white.

Ideas:

Typical enumeration questions.

1. Each grid can be operated at most once.

2. After the operation of the first column is determined, the following operations are also determined.

An integer can be used to represent the state of black and white, that is, state compression.

code:

poorly written

#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define int long long
using namespace std;
const int N=1e5+7;
const int INF=0x3f3f3f3f;

char b[5][5];
char d[5][5];
void cal(int x,int y)
{
    
    
	if(d[x][y]=='w')d[x][y]='b';
	else d[x][y]='w';
	if(x-1>=0)
	{
    
    
		if(d[x-1][y]=='w')d[x-1][y]='b';
		else d[x-1][y]='w';
	}
	if(x+1<4)
	{
    
    
		if(d[x+1][y]=='w')d[x+1][y]='b';
		else d[x+1][y]='w';
	}
	if(y-1>=0)
	{
    
    
		if(d[x][y-1]=='w')d[x][y-1]='b';
		else d[x][y-1]='w';
	}
	if(y+1<4)
	{
    
    
		if(d[x][y+1]=='w')d[x][y+1]='b';
		else d[x][y+1]='w';
	}
}
bool check()
{
    
    
	for(int i=0;i<4;++i)
	{
    
    
		for(int j=0;j<4;++j)
		{
    
    
			if(d[i][j]=='b')return 0;
		}
	}
	return 1;
}
bool check2()
{
    
    
	for(int i=0;i<4;++i)
	{
    
    
		for(int j=0;j<4;++j)
		{
    
    
			if(d[i][j]=='w')return 0;
		}
	}
	return 1;
}
void init()
{
    
    
	for(int i=0;i<4;++i)
	{
    
    
		for(int j=0;j<4;++j)
		{
    
    
			d[i][j]=b[i][j];
		}
	}
}
signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	for(int i=0;i<4;++i)
	{
    
    
		for(int j=0;j<4;++j)
		{
    
    
			cin>>b[i][j];
		}
	}
	int ans=INF;//--1111 15
	for(int temp=0;temp<16;++temp)//枚举第一类的操作
	{
    
    
		init();
		int cnt=0;
		for(int i=0;i<4;++i)
		{
    
    
			if((temp>>i)&1)
			{
    
    
				cal(i,0);
				++cnt;
			}
		}
		for(int i=0;i<3;++i)
		{
    
    
			for(int j=0;j<4;++j)
			{
    
    
				if(d[j][i]=='b')//全白的情况
				{
    
    
					cal(j,i+1);
					++cnt;
				}
			}
		}
		if(check())ans=min(ans,cnt);
	}

	for(int temp=0;temp<16;++temp)
	{
    
    
		init();
		int cnt=0;
		for(int i=0;i<4;++i)
		{
    
    
			if((temp>>i)&1)
			{
    
    
				cal(i,0);
				++cnt;
			}
		}
		for(int i=0;i<3;++i)
		{
    
    
			for(int j=0;j<4;++j)
			{
    
    
				if(d[j][i]=='w')//全黑的情况
				{
    
    
					cal(j,i+1);
					++cnt;
				}
			}
		}
		if(check2())ans=min(ans,cnt);
	}

	if(ans==INF)cout<<"Impossible"<<endl;
	else cout<<ans<<endl;
	return 0;
}

1.17 Subsequence

The main idea of ​​the topic:

In an array, find the minimum length of the sum of consecutive substrings not less than S.

Ideas:

Ruler method/double pointer.

Board questions.

Let the bug eat from the left, move the head r, update the minimum body length when it is full, and then pull it out from the tail l to continue eating.

code:
#include<iostream>
#include<algorithm>
#include<cstring>
#define int long long
#define endl '\n'
using namespace std;
const int N=1e5+7;
const int INF=0x3f3f3f3f;

int a[N];

signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int t;
	cin>>t;
	while(t--)
	{
    
    
		int n,m;
		cin>>n>>m;
		for(int i=0;i<n;++i)
		{
    
    
			cin>>a[i];
		}
		int ans=INF;
		int sum=0;
		int l=0,r=0;
		while(1)
		{
    
    
			while(sum<m&&r<n)
			{
    
    
				sum+=a[r++];
			}
			if(sum<m)break;
			ans=min(ans,r-l);
			sum-=a[l++];
		}
		if(ans==INF)cout<<0<<endl;
		else cout<<ans<<endl;
	}
	return 0;
}

1.18 Matrix elimination game

insert image description here

Enter a description:
第一行三个整数
接下来行每行个整数表示矩阵中各个单元格的权值。
Output description:
输出一个整数表示牛妹能获得的最大分数。

Example 1

enter

3 3 2
101 1 102
1 202 1
100 8 100

output

414
Remark:

insert image description here

The main idea of ​​the topic:

An n*m matrix, you can select one row or one column, and add the sum, then the row or column becomes 0, select k at most, and find the maximum sum.

Ideas:

enumeration, greedy, prefix and .

When k>=min(n,m), you can always add all the numbers to the sum, and the answer at this time is sum.

First, only consider the case when all rows or columns are taken, and add up the top k largest ones to get the largest one at a time.

Then consider the case where there are rows and columns, find the prefix sum of each row and column, and take out the largest row or column first. (Personally, I think there will be some problems)

code:
#include<iostream>
#include<cstring>
#include<algorithm>
#define int long long
using namespace std;
const int N=5e6+7;

int a[20][20];
int l[20];
int up[20];
int temp[20];

signed main()
{
    
    
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int n,m,k;
	cin>>n>>m>>k;
	int sum=0;
	for(int i=1;i<=n;++i)
	{
    
    
		for(int j=1;j<=m;++j)
		{
    
    
			cin>>a[i][j];
			sum+=a[i][j];
			l[i]+=a[i][j];
			up[j]+=a[i][j];
		}
	}
	if(k>=min(n,m))cout<<sum<<endl;
	else
	{
    
    
		int ans=0;
		for(int i=1;i<=n;++i)
		{
    
    
			temp[i]=l[i];
		}
		sort(temp+1,temp+1+n,greater<int>());
		for(int i=1;i<=n;++i)
		{
    
    
			temp[i]+=temp[i-1];
		}
		ans=max(ans,temp[k]);
		for(int i=1;i<=m;++i)
		{
    
    
			temp[i]=up[i];
		}
		sort(temp+1,temp+1+m,greater<int>());
		for(int i=1;i<=m;++i)
		{
    
    
			temp[i]+=temp[i-1];
		}
		ans=max(ans,temp[k]);
		int ans2=0;
		while(k--)
		{
    
    
			int Max=0;
			int pos=0;
			bool flag=0;
			for(int i=1;i<=n;++i)
			{
    
    
				if(Max<l[i])
				{
    
    
					Max=l[i];
					pos=i;
					flag=0;
				}
			}
			for(int i=1;i<=m;++i)
			{
    
    
				if(Max<up[i])
				{
    
    
					Max=up[i];
					pos=i;
					flag=1;
				}
			}
			if(flag)
			{
    
    
				up[pos]=0;
				for(int i=1;i<=n;++i)
				{
    
    
					l[i]-=a[i][pos];
				}
			}
			else
			{
    
    
				l[pos]=0;
				for(int i=1;i<=m;++i)
				{
    
    
					up[i]-=a[pos][i];
				}
			}
			ans2+=Max;
		}
		cout<<max(ans,ans2)<<endl;
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/Story_1419/article/details/120081814