Complete problem solution of the 14th Lanqiao Cup Provincial Competition C/C++ Group B

There is no evaluation, so I don’t know if it’s correct or not, it’s just a sample.

Question A: Date Statistics

Total score for this question: 5 points

【Problem Description】

Xiaolan now has an array with a length of 100, and the value of each element in the array is in the range of 0 to 9. The elements in the array look like this from left to right:

5 6 8 6 9 1 6 1 2 4 9 1 9 8 2 3 6 4 7 7 5 9 5 0 3 8 7 5 8 1 5 8 6 1 8 3 0 3 7 9 2 7 0 5 8 8 5 7 0 9 9 1 9 4 4 6 8 6 3 3 8 5 1 6 3 4 6 7 0 7 8 2 7 6 8 9 5 6 5 6 1 4 0 1 0 0 9 4 8 0 9 1 2 8 5 0 2 5 3 3

Now he wants to find some subsequences from this array that satisfy the following conditions:

    1. The length of the subsequence is 8;

    2. This subsequence can be formed into a date in yyyymmdd format in subscript order, and the date is required to be a date on a certain day in 2023, such as 20230902, 20231223. yyyy represents the year, mm represents the month, and dd represents the number of days. When the length of the month or day is only one digit, a leading zero is required. Please help Xiaolan calculate how many different dates in 2023 can be found based on the above conditions. You only need to count the same date once.

【Answer submission】235

This is a fill-in-the-blank question, you just need to calculate the result and submit it. The result of this question is an integer. Only fill in this integer when submitting the answer. No points will be awarded if you fill in excess content.

The method is clumsy, but the idea is extremely simple. Even though there are eight layers of loops, the first four layers are close to none, and the efficiency is quite high.

#include<bits/stdc++.h>
#define LL long long
using namespace std;
bool  date_flag[1232];  //月+日 的范围是 01-01 到 12-31  ,找到哪个日期,就标记为 true; 
int main(){
	int A[]={5, 6, 8, 6, 9, 1, 6, 1, 2, 4, 9, 1, 9, 8, 2, 3, 6, 4, 7, 7, 5, 9, 5, 0, 3, 8, 7, 5, 8, 1, 5, 8, 6, 1, 8, 3, 0, 3, 7, 9, 2,
			7, 0, 5, 8, 8, 5, 7, 0, 9, 9, 1, 9, 4, 4, 6, 8, 6, 3, 3, 8, 5, 1, 6, 3, 4, 6, 7, 0, 7, 8, 2, 7, 6, 8, 9, 5, 6, 5, 6, 1, 4, 0, 1,
			0, 0, 9, 4, 8, 0, 9, 1, 2, 8, 5, 0, 2, 5, 3, 3};
	for(int a=0; a<=100-8; a++){   //2
		if(A[a]!=2)continue;
		
		for(int b=a+1; b<=100-7; b++){  //0
			if(A[b]!=0)continue;
			
			for(int c=b+1; c<=100-6; c++){  //2
				if(A[c]!=2)continue;
				
				for(int d=c+1; d<=100-5; d++){  //3
					if(A[d]!=3)continue;
					
					for(int e=d+1; e<=100-4; e++){ //月份第一个数 
						if(A[e]>1)continue;
						
						for(int f=e+1; f<=100-3; f++){  //月第二个数 
							int month=A[e]*10+A[f];  //月份
							if(month>12 || month==0)continue;
							
							for(int g=f+1; g<=100-2; g++){//日第一个数 
								if(A[g]>3)continue;
								
								for(int h=g+1; h<=100-1; h++){//日第二数 
									int day=A[g]*10+A[h]; // 日 
									if(day>31 || day==0)continue;                    //需要注意日期合法性, 比如:2月31日就不合法 
									
									int i = month*100+day;
								//	printf("2023 %04d\n",i);  //可以输出看一下 
									date_flag[i]=true;
	}   }   }   }   }   }   }   }
	int ans=0,uu=0;
	for(int i=101; i<1231; i++){
		
		if(i==229 || i==230 || i==231 || i==431 || i==631 || i==931 || i==1131 ) //不合法日期 (2023年不是润年) 
			continue;
		ans+=date_flag[i];  
	}				
	cout<<ans;						
	return 0;	
}

Question B: 01 Entropy of string

Total score for this question: 5 points

【Problem Description】

For a 01 string of length n S = x1 x2 x3...xn, the Shannon information entropy is defined as H(S ) = −Σ n 1 p(xi)log2 (p(xi)), where p(0) , p(1) represents the proportion of occurrences of 0 and 1 in this 01 string. For example, for S = 100, the information entropy H(S) = − 1/3 log2 ( 1/3 ) – 2/3 log2 ( 2/3 ) – 2/3 log2 ( 2/3 ) = 1.3083. For a 01 string with a length of 23333333, if its information entropy is 11625907.5798, and the number of 0 occurrences is less than 1, then how many times does 0 appear in this 01 string?

【Answer submission】11027421

This is a fill-in-the-blank question, you just need to calculate the result and submit it. The result of this question is an integer. Only fill in this integer when submitting the answer. No points will be awarded if you fill in excess content. 

#include<bits/stdc++.h>
#define LL long long
using namespace std;

int main(){
	//设 有 x 个 ‘0’ 和 y 个 ‘1’ ;则有x+y= 23333333,即 y=23333333-x , 
	//      因为题目告诉了  0 出现次数比 1 少,也即是 x<=23333333/2 ,
	//                                 ‘0’占比 x/(x+y)
	//                                 ‘1’占比 y/(x+y)  
	//计算机最不怕的就是麻烦,开找
	double Hs=11625907.5798;
	for(double x=23333333/2; x>=1; x-- ){  //刷题经验给我的感觉就是要求的 x 一定很大,所以我选择反过来循环 
		double y=23333333-x;
		double p0=x/(x+y);
		double p1=y/(x+y);   // p1=1.0-p0;
		double result = x * ( - p0 * ( log(p0)/log(2) ) ) + y * ( - p1 * ( log(p1)/log(2) ) );
		
		if(11625907.5797<result && result<11625907.5799)  //精度问题,没办法用等于 
			printf("x=%.0f  result=%f\n",x,result);		
	}                                                     
	return 0;	
}

Test Question C: Smelting Metals

Time limit: 1.0s Memory limit: 256.0MB Total score for this question: 10 points

【Problem Description】

Xiaolan has a magical furnace that is used to smelt ordinary metal O into a special metal X. This furnace has an attribute V called the conversion rate. V is a positive integer, which means that consuming V ordinary metal O can exactly smelt a special metal X. When the number of ordinary metal O is less than V, smelting cannot continue. Now N smelting records are given, each record contains two integers A and B, which means that A ordinary metal O was invested this time, and B special metal X was finally smelted. Each record is independent, which means that the ordinary metal O that was not consumed last time will not be accumulated into the next smelting. Based on these N smelting records, please guess what the minimum and maximum values ​​of the conversion rate V may be. The question ensures that the evaluation data does not have no solution.

【Input format】

The first line contains an integer N, representing the number of smelting records. Next, enter N lines, each line contains two integers A and B, with the meanings as stated in the title.

[Output format]

   Output two integers, representing the possible minimum and maximum values ​​of V respectively, separated by spaces.

[Sample input]

3

75  3

53  2

59  2

[Sample output]

20  25

[Sample description]

When V = 20, there are: ⌊ 75/ 20 ⌋ = 3, ⌊ 53/ 20 ⌋ = 2, ⌊ 59/ 20 ⌋ = 2, which can be seen to be consistent with all smelting records.

  When V = 25, there are: ⌊ 75 /25 ⌋ = 3, ⌊ 53/ 25 ⌋ = 2, ⌊ 59/ 25 ⌋ = 2, which can be seen to be consistent with all smelting records.

And no qualified V value smaller than 20 or larger than 25 can be found.

[Evaluation use case scale and agreement]

For 30% of the evaluation cases, 1 ≤ N ≤ 10^2.

For 60% of the evaluation cases, 1 ≤ N ≤ 10^3.

For 100% of the evaluation cases, 1 ≤ N ≤ 10^4, 1 ≤ B ≤ A ≤ 10^9.

#include<bits/stdc++.h>
#define LL long long
using namespace std;

int main(){  //10分题,想啥呢,没那么负责,很简单的,每次都判断可去范围就好了 
	int V_max=0x3f3f3f3f ,V_min=0;
	int N;
	cin>>N;
	while(N--){
		int A,B;
		cin>>A>>B;
		
		//本次中,冶炼一个特殊金属至少消耗 Vmin 才能满足本次冶炼 B 个的条件 
		int Vmin=A/(B+1)+1;
		
		//本次中,冶炼一个特殊金属最多消耗 Vmax 才能满足本次冶炼 B 个的条件
		int Vmax=A/B;
		
		V_min=max(V_min, Vmin); //所有最小消耗中取最大值才能都满足 
		
		V_max=min(V_max, Vmax);	//所有最大消耗中取最小值才能都满足
	}

    cout<<V_min<<" "<<V_max<<endl;
	                                                
	return 0;	
}

Test question D: Plane landing

Time limit: 2.0s Memory limit: 256.0MB Total score for this question: 10 points

【Problem Description】

 N planes are preparing to land at an airport with only one runway. Among them, the i-th plane arrives at the airport at time Ti. When it arrives, its remaining fuel can continue to hover for Di unit time, that is, it can start landing at time Ti at the earliest and at time Ti + Di at the latest. The landing process takes Li units of time. When one plane completes landing, another plane can immediately start landing at the same time, but it cannot start landing before the previous plane completes its landing. Please judge whether all N planes can land safely.

【Input format】

The input contains multiple sets of data. The first line contains an integer T, representing the number of groups of test data. For each set of data, the first row contains an integer N. The following N lines each contain three integers: Ti, Di and Li.

[Output format]

For each set of data, output YES or NO, indicating whether all can land safely.

[Sample input]

2

3

0 100 10

10 10 10

0 2 20

3

0 10 20

10 10 20

20 10 20

[Sample output]

YES

NO

[Sample description]

 For the first set of data, the third aircraft can be arranged to start landing at time 0 and complete the landing at time 20. Arrange for the second plane to start landing at 20:00 and complete the landing at 30:00. Arrange for the first plane to start landing at 30:00 and complete the landing at 40:00.

 For the second set of data, no matter how arranged, there will be planes that cannot land in time.

[Evaluation use case scale and agreement]

For 30% of the data, N ≤ 2.

For 100% of the data, 1 ≤ T ≤ 10, 1 ≤ N ≤ 10, 0 ≤ Ti, Di, Li ≤ 10^5.

If nothing else, I estimate that this solution is only effective for 50% of the assessments

#include<bits/stdc++.h>
#define LL long long
using namespace std;
struct A{
	int T,D,L;
	int late_time;//最迟降落时间 (T+D) 
};
bool cmp(A x, A y){ return x.late_time < y.late_time; }//最迟降落时间升序 
bool fun(A *ff, int n){
    int now_time=0;  //当前时间 	
	sort(ff,ff+n,cmp); //按照最迟降落时间先后 	
	for(int i=0;i<n-1;i++){
		if(ff[i].T+ff[i].L>ff[i+1].late_time) return false;	//最早降落时间 + 降落时间 > 下一架飞机最次迟降落时间		
		now_time+=ff[i].L; //降落后当前时间 					 
		if(now_time>ff[i+1].late_time) return false;  //当前时间 >  下一架飞机最次迟降落时间	
	} 
	return true;	
}
int main(){  
	int T;
	cin>>T;
	while(T--){
		int n;
		cin>>n;
		A ff[n];
		for(int i=0; i<n; i++){
			cin>>ff[i].T>>ff[i].D>>ff[i].L; 
			ff[i].late_time=ff[i].T+ff[i].D;
		}
		
	if(fun(ff, n))  cout<<"YES"<<endl;		
	else         cout<<"NO"<<endl;			
	}	                                      
	return 0;	
}

Test question E: Solitaire sequence

Time limit: 1.0s Memory limit: 256.0MB Total score for this question: 15 points

【Problem Description】

For an integer sequence of length K: A1, A2, . . . , AK, we call it a solitaire sequence if and only if the first digit of Ai is exactly equal to the last digit of Ai−1 (2 ≤ i ≤ K). For example, 12, 23, 35, 56, 61, 11 is a solitaire sequence; 12, 23, 34, 56 is not a solitaire sequence because the first digit of 56 is not equal to the last digit of 34. All integer sequences of length 1 are solitaire sequences. Now given a sequence A1, A2, . . . , AN of length N, please calculate the minimum number of numbers that can be deleted from it so that the remaining sequence is a solitaire sequence?

【Input format】

The first line contains an integer N. The second line contains N integers A1, A2, . . . , AN.

[Output format]

An integer represents the answer.

[Sample input]

5

11 121 22 12 2023

[Sample output]

1

[Sample description]

Delete 22, and the remaining 11, 121, 12, and 2023 are the Solitaire sequence.

[Evaluation use case scale and agreement]

For 20% of the data, 1 ≤ N ≤ 20.

For 50% of the data, 1 ≤ N ≤ 10000.

For 100% of the data, 1 ≤ N ≤ 10^5, 1 ≤ Ai ≤ 10^9. All Ai are guaranteed not to contain leading 0s.

#include<bits/stdc++.h>
#define LL long long
using namespace std;
//(我下意识想到了第一题)题目要求的是 最少 从中删除多少个数,  
//                       也就是求最长的接龙子序列嘛 
//                       动态规划典型例题之一:求最长子序列
//       虽然才到第5题,但是今年蓝桥杯明显想搞事情,动态规划就动态规划嘛,搞这么隐秘干嘛。 

int tou[100005],wei[100005];//第 i 个数的头、第 i 个数的尾
int dp[100005];// dp[i]:表示前 i 个数中,以第 i 个数作为子序列结尾的最长的接龙子序列长度 
//                                              注意:不以 i 结尾的接龙子序列也可能会更长 
int main(){ 
	int n;
	cin>>n;
	for(int i=0; i<n; i++){
		string s;
		cin>>s;
		tou[i]=s[0]-'0';            //头
		wei[i]=s[s.size()-1]-'0';   //尾   
	}
	
	int max_size=0;  //记录过程中最长接龙子序列 
	for(int i=0; i<n; i++){    
		dp[i]=1;
		for(int j=0; j<i; j++){
			if(wei[j]==tou[i])  //第 j (j<i)个数的尾b[j]等于第 i 个数的头a[i]时
				dp[i]=max(dp[i],dp[j]+1); //拼接成功,长度 + 1 
		}
		max_size=max(max_size,dp[i]);
	}
	cout<<n-max_size;
	return 0;
}

Question F: Number of islands

Time limit: 2.0s Memory limit: 256.0MB Total score for this question: 15 points

【Problem Description】

Xiaolan got a grid map of size M × N, which can be regarded as a two-dimensional array containing only the characters '0' (representing sea water) and '1' (representing land). The outside of the map can be regarded as All are seawater, and each island is formed by connecting adjacent '1's in the four directions of up/down/left/right. In the grid occupied by island A, if k different grids can be selected from them, their coordinates can form an arrangement like this: (x0, y0), (x1, y1), . . . ,(xk− 1, yk−1), where (x(i+1)%k , y(i+1)%k) is obtained by (xi , yi) moving up/down/left/right once (0 ≤ i ≤ k − 1), at this time, these k grids form a "ring". If all the grids occupied by another island B are located inside this "ring", we will regard island B as a sub-island of island A. If B is a sub-island of A, and C is a sub-island of B, then C is also a sub-island of A. How many islands are there in total on this map? There is no need to count the number of sub-islands when performing statistics.

【Input format】

    The first line contains an integer T, indicating that there are T sets of test data. Next, enter the T group of data. For each set of data, the first line contains two integers M and N separated by spaces, indicating the map size; then enter M lines, each line containing N characters, and the characters can only be '0' or '1'.

[Output format]

For each set of data, output a line containing an integer representing the answer.

[Sample input]

2

5 5

01111

11001

10101

10001

11111

5 6

111111

100001

010101

100001

111111

[Sample output]

1

3

[Sample description]

For the first set of data, there are two islands, distinguished by different numbers below: 01111 11001 10201 10001 11111 Island 2 is inside the "ring" of Island 1, so Island 2 is a sub-island of Island 1, and the answer is 1. For the second set of data, there are three islands, distinguished below by different numbers: 111111 100001 020301 100001 111111

Note that Island 3 is not a sub-island of Island 1 or Island 2, because there are no "rings" in Island 1 or Island 2.

[Evaluation use case scale and agreement]

For 30% of the evaluation cases, 1 ≤ M, N ≤ 10.

For 100% of the evaluation cases, 1 ≤ T ≤ 10, 1 ≤ M, N ≤ 50.

Personally, this question is the most difficult for me, and it is also the longest one to write.

#include<bits/stdc++.h>
#define LL long long int
using namespace std;
const int INF=0x3f3f3f3f;
const int N=55;
char Map[N][N];
int i_min,i_max,j_min,j_max;
int start_i,start_j;


void teke_map(int r_min, int c_min,int r_max, int c_max){
	stack<int>stk;
	for(int i=r_min; i<=r_max; i++){
		int flag=0;  //既然是环岛,任意行/列必定被两个 “2”夹着 
		for(int j=c_min; j<=c_max; j++){
			if(Map[i][j]=='2')	++flag;				
			if(flag && flag%2!=0 && Map[i][j]=='1') stk.push(j);			
			if(flag%2!=0){
				while(!stk.empty()){
					Map[i][stk.top()]='2';
					stk.pop();
}	}	}	}	}
			
void __islands(int i, int j, int flag){   
//flag=1表示从左边来的,flag=2表示从上边来的,flag=3表示从右边来的,flag=4表示从下边来的 

	if(Map[i][j]=='2' && i==start_i && j==start_j  ){              //发现环岛
		teke_map(i_min,j_min,i_max,j_max); //清除内部岛屿 
		return;
	}	
	if(Map[i][j]=='0' || Map[i][j]=='2')return; 
	Map[i][j]='2'; //标记计算过了,也能防止递归回头 
	
	//该岛范围 
	i_min=min(i, i_min);	j_min=min(j, j_min);
	i_max=max(i, i_max);    j_max=max(j, j_max);
	 		
	//递归策略:先右、再下、再左,最后上,顺时针外扩
	// 0 行和 0 列都没使用,均为 0 ,可以看作海,不用担心边界; 
	if(flag!=3)  __islands(i+1, j, 1);// 往右走 
	if(flag!=4)  __islands(i, j+1, 2);// 往下走
	if(flag!=1)  __islands(i-1, j, 3);// 往左走
	if(flag!=2)  __islands(i, j-1, 4);// 往上走
}

void find_islands(int si, int sj){
	i_min   = INF;		i_max   =  0;
	j_min   = INF;		j_max   =  0;
	start_i =  si;		start_j = sj;
	__islands(si, sj, 0);
};

int main(){ 
	int T;	cin>>T;
	while(T--){
		memset(Map,'0',sizeof Map);
		int m,n;
		cin>>m>>n;
		for(int i=1; i<=m; i++)
			for(int j=1; j<=n; j++)
			cin>>Map[i][j];				
			
		int ans=0;
		for(int i=1; i<=m; i++){			
			for(int j=1; j<=n; j++){
				if(Map[i][j]=='1'){
					ans++;
					find_islands(i,j);
				}				
			}
		}
		cout<<ans<<endl;	
	} 
	return 0;
}

Test question G: Substring abbreviation

Time limit: 1.0s Memory limit: 256.0MB Total score for this question: 20 points

【Problem Description】

A very new abbreviation method is becoming popular in the programmer circle: for a string, only the first and last characters are retained, and all characters between the first and last characters are replaced with the length of this part. For example, internationalization is abbreviated as i18n, Kubernetes (note that the hyphen is not part of the string) is abbreviated as K8s, Lanqiao is abbreviated as L5o, etc. In this question, we stipulate that strings with a length greater than or equal to K can use this abbreviation method (strings with a length less than K are not worthy of using this abbreviation). Given a string S and two characters c1 and c2, please calculate how many substrings of S starting with c1 and ending with c2 can use this abbreviation?

【Input format】

The first line contains an integer K.

The second line contains a string S and two characters c1 and c2.

[Output format]

An integer represents the answer.

[Sample input]

4

abababdb ab

[Sample output]

6

[Sample description]

The substring that meets the conditions is as follows, with the substring in square brackets:

[abab]abdb

[ababab]db

[abababdb]

ab[abab]db

ab[ababdb]

abab [abdb]

[Evaluation use case scale and agreement]

For 20% of the data, 2 ≤ K ≤ |S | ≤ 10000.

For 100% of the data, 2 ≤ K ≤ |S | ≤ 5 × 105. S contains only lowercase letters. c1 and c2 are both lowercase letters. |S | represents the length of string S.

20 points, it’s a bit too simple, I don’t believe it, there may be some pitfalls, such as timeout.

#include<bits/stdc++.h>
#define LL long long
using namespace std;
int CC1[500000];
int CC2[500000];
int main(){  
	int k;	cin>>k;
	string S;  
	char c1,c2;	
	cin>>S>>c1>>c2;
	int len=S.size();
	int s=0,t=0;
	for(int i=0; i<len; i++){
		if(S[i]==c1) CC1[s++]=i;
		if(S[i]==c2) CC2[t++]=i;
	}
	LL ans=0;
	for(int i=0; i<s; i++){
		for(int j=0; j<t; j++)
			if( CC2[j]-CC1[i] >= k-1 )ans++;		
	}
	cout<<ans;                                      
	return 0;	
}

Test H: Integer deletion

Time limit: 1.0s Memory limit: 256.0MB Total score for this question: 20 points

【Problem Description】

Given an integer sequence of length N: A1, A2, . . . , AN. You have to repeat the following operations K times:

Each time, select the smallest integer in the sequence (if there is more than one minimum value, select the frontmost one) and delete it. And add the deleted value to the integer adjacent to it. Output the sequence after K operations.

【Input format】

The first line contains two integers N and K. The second line contains N integers, A1, A2, A3, . . . , AN.

[Output format]

Output N − K integers, separated by a space, representing the sequence after K operations.

[Sample input]

5 3

1 4 2 8 7

[Sample output]

17 7

[Sample description]

 The sequence changes as follows. The number in the square brackets is the number selected in the current operation:

[1] 4 2 8 7

5 [2] 8 7

[7] 10 7

17 7

[Evaluation use case scale and agreement]

For 20% of the data, 1 ≤ K < N ≤ 10000.

For 100% of the data, 1 ≤ K < N ≤ 5 × 10^5, 0 ≤ Ai ≤ 10^8.

#include<bits/stdc++.h>
#define LL long long
using namespace std;
map<int, int >k_v_map;          
bool cmp(const pair<int, int> left,const pair<int,int> right){
	return left.second < right.second;
}
int main(){ 
	int N,K;
	cin>>N>>K;
	for(int i=0; i<N; i++){
		cin>>k_v_map[i];
	}	
	map<int, int>::iterator it;  //迭代指针 
	while(K--){		
		it = min_element(k_v_map.begin(),k_v_map.end(),cmp);//获取最小值键值对的迭代指针 
		int Ai=it->second;  //最小值 
		if(it!=k_v_map.begin()){//不是第一个时 
			it--;
			it->second+=Ai;   //前一个元素加上 Ai 
			it++;
		}
		if(it!=k_v_map.end()){//不是第一个时 
			it++;
			it->second+=Ai; //后一个元素加上 Ai
			it--;
		}		
 		k_v_map.erase(it); //删除最小值键值对		 
	}	
	for(it = k_v_map.begin(); it != k_v_map.end(); it++)
   	 	cout<<it->second<<" ";//输出value值
	return 0;
}

Question I: Scenic Area Tour Guide

Time limit: 5.0s Memory limit: 256.0MB Total score for this question: 25 points

【Problem Description】

There are a total of N scenic spots in a certain scenic spot, numbered 1 to N. There are N − 1 two-way shuttle bus lines connecting the attractions, forming a tree-like structure. Traveling between attractions can only be done via these shuttle buses, which takes a certain amount of time. Xiao Ming is a senior tour guide in this scenic spot. He takes guests to visit K scenic spots in a fixed order every day: A1, A2, . . . , AK. Due to time reasons today, Xiao Ming decided to skip one of the attractions and only take tourists to visit K − 1 of them in order. Specifically, if Xiao Ming chooses to skip Ai, then he will take tourists to visit A1, A2, . . . , Ai−1, Ai+1, . . . , AK, (1 ≤ i ≤ K) in order. For any AI, please calculate how much time Xiao Ming will need to spend on the shuttle bus between the attractions if he skips this attraction?

【Input format】

The first line contains 2 integers N and K. The following N − 1 lines, each line contains 3 integers u, v and t, represent that there is a shuttle bus line between attractions u and v, which takes t units of time. The last line contains K integers A1, A2, . . . , AK represents the original tour route.

[Output format]

Output K integers, where the i-th represents the time spent on the shuttle bus after skipping Ai.

[Sample input]

6 4

1 2 1

1 3 1

3 4 2

3 5 2

4 6 3

2 6 5 1

[Sample output]

10 7 13 14

[Sample description]

 The original route is 2 → 6 → 5 → 1.

When skipping 2, the route is 6 → 5 → 1, where 6 → 5 takes time 3 + 2 + 2 = 7, 5 → 1 takes time 2 + 1 = 3, and the total time spent is 10.

When skipping 6, the route is 2 → 5 → 1, where 2 → 5 takes time 1 + 1 + 2 = 4, 5 → 1 takes time 2 + 1 = 3, and the total time spent is 7.

When skipping 5, the route is 2 → 6 → 1, where 2 → 6 takes time 1 + 1 + 2 + 3 = 7, 6 → 1 takes time 3 + 2 + 1 = 6, and the total time spent is 13.

When 1 is skipped, the route is 2 → 6 → 5, where 2 → 6 takes time 1 + 1 + 2 + 3 = 7, 6 → 5 takes time 3 + 2 + 2 = 7, and the total time spent is 14.

[Evaluation use case scale and agreement]

For 20% of the data, 2 ≤ K ≤ N ≤ 10^2.

For 40% of the data, 2 ≤ K ≤ N ≤ 10^4.

For 100% of the data, 2 ≤ K ≤ N ≤ 10^5, 1 ≤ u, v, Ai ≤ N, 1 ≤ t ≤ 10^5. Ensure that Ai is different in every pair.

 /* 40% 的苟分版 */ 
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int INF=0x3f3f3f3f;
const int N=10000;
int dp[N][N];//二维数组根本开不了这么大          
     
void floyd(int n){  //floyd算法肯定超时O(n^3) 
	for(int k=1; k<=n; k++)
		for(int i=1; i<=n; i++)
			for(int j=1; j<=n; j++)
				dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
}         
  
int main(){ 
	//初始化化 
	memset(dp,INF,sizeof dp);
	for(int i=0; i<N; i++) dp[i][i]=0;  	
	//输入边权值	
	int n,k;
	cin>>n>>k;	
	int x,y,z;
	for(int i=0; i<n-1; i++){
		cin>>x>>y>>z;
		dp[x][y]=min(dp[x][y],z); //去重边
		dp[y][x]=min(dp[y][x],z); //去重边 
	}
	int KK[k+1];
	for(int i=1; i<=k; i++) cin>>KK[i];  //KK[0]未用; 	
	floyd(n); //执行flyd算法;	
	//解决方案
	LL sum=0;
	for(int i=2; i<=k; i++){  
		sum+=dp[KK[i-1]][KK[i]];
	cout<<sum-dp[KK[1]][KK[2]]<<" ";//不去第一个计划游览点 
	for(int i=2; i<=k-1; i++){   //不去中间的第 i 个计划游览点 
		cout<<sum-dp[KK[i-1]][KK[i]]-dp[KK[i]][KK[i+1]]+dp[KK[i-1]][KK[i+1]]<<" ";
	}	
	cout<<sum-dp[KK[k-1]][KK[k]];//不去最后个计划游览点 
	return 0;
}

  /* AC版 */ 
#include<bits/stdc++.h>
#define LL long long int
using namespace std;
const int INF=0x3f3f3f3f;
const int N=100005;

struct A{   //结构体中用 map 
	map<int, int>m;
}P[N]; 

bool flag=false;  
LL goal_time=0;  //记录 Ai 到 Aj 摆渡车花的消耗时间 

void _time(int last_come_p, int i, int goal_p, LL time){
	if(flag) return;   //得到消耗的时间了 
	if(i==goal_p){     
		goal_time=time; //记录到达目标消耗的时间 
		flag=true;
		return;
	}
	else{			
		//P[i]的map一定不是空的,不用判断,因为至少会存着一个来的路 
		for(map<int, int>::iterator it = P[i].m.begin(); it!=P[i].m.end(); it++){ 			
			if(flag) return; 		
			if(  it->first == last_come_p) 	continue;  //别回头 
			_time(i, it->first, goal_p, time + it->second);	//递归寻找 
		}
	}	
}

LL spend_time(int s,int d){ //初始化 flag、goal_time,顺便分个模块出来 
	flag=false;
	goal_time=0; 
	_time(0,s,d,0);
	return goal_time; 
}

int main(){ 
	int n,k;
	cin>>n>>k;	
	int u,v,t;
	for(int i=1; i<n; i++){
		cin>>u>>v>>t;
		P[u].m[v]=t;
		P[v].m[u]=t;
	}
	int K[k+1];      //K[0]不用
	LL  Time[k+1];   //Time[0]不用,Time[1]记录总时间,Time[i]记录 Ai-1 到 Ai 消耗在摆渡车上的时间 
	Time[1]=0;
	cin>>K[1];	
	for(int i=2; i<=k; i++) {
		cin>>K[i];		
		Time[i]=spend_time(K[i-1],K[i]); 				
		Time[1]+=Time[i];  //求总耗时 
	}   			
	cout<<Time[1]-Time[2]<<" ";//不去第一个计划游览点 
	for(int i=2; i<=k-1; i++){   //不去中间的第 i 个计划游览点 		 
		cout<<Time[1]-Time[i]-Time[i+1]+ spend_time(K[i-1],K[i+1])<<" ";
	}	
	cout<<Time[1]-Time[k];//不去最后个计划游览点 
	return 0;
}

Question J: Cutting down a tree

Time limit: 1.0s Memory limit: 256.0MB Total score for this question: 25 points

【Problem Description】

 Given a tree consisting of n nodes and m non-repeating pairs of unordered numbers (a1, b1), (a2, b2), . . . , (am, bm), where ai are different from each other, bi Different from each other, ai, bj(1 ≤ i, j ≤ m). Xiao Ming wants to know if he can choose to cut an edge on a tree so that for each (ai, bi), ai and bi are not connected. If so, output the number of the edge that should be cut (the number starts from 1 in the order of input). , otherwise output -1.

【Input format】

 Input a total of n + m lines, the first line is two positive integers n, m. In the following n − 1 lines, each line has two positive integers xi and yi representing the two endpoints of the i-th edge. The following m lines contain two positive integers ai and bi in each line.

[Output format]

 One integer per line represents the answer. If there are multiple answers, the one with the largest number is output.

[Sample input]

6 2

1 2

2 3

4 3

2 5

6 5

3 6

4 5

[Sample output]

 4

[Sample description]

 After disconnecting the second edge, two connected blocks are formed: {3, 4}, {1, 2, 5, 6}, which satisfy that 3 and 6 are not connected, and 4 and 5 are not connected. After disconnecting the 4th edge, two connected blocks are formed: {1, 2, 3, 4}, {5, 6}, which also satisfy that 3 and 6 are not connected, and 4 and 5 are not connected. 4 is the higher number, so the answer is 4.

[Evaluation use case scale and agreement]

For 30% of the data, 1 < n ≤ 1000 is guaranteed.

For 100% of the data, it is guaranteed that 1 < n ≤ 10^5, 1 ≤ m ≤ n/2.

#include<bits/stdc++.h>
#define LL long long int
using namespace std;
const int N=100005;

struct A{   //结构体中用maps
	map<int, int>maps;   //节点D[i] 链接着节点  ->first,    这是第 ->second 条边    
}D[N]; 

map<int, int> side;
bool flag=false;  

void __sides(int last_i, int i, int d){	
	if(flag) return;   //找到了 
	if(i==d){     
		flag=true;
		return;
	}
	else{			
		//D[i]的 map一定不是空的,不用判断,因为至少会存着一个来的路 
		for(map<int, int>::iterator it = D[i].maps.begin(); it!=D[i].maps.end(); it++){ 							
			if(  it->first == last_i) 	continue;  //别回头 
			side[it->second]=1;    //记录边 
			__sides(i, it->first, d);	//递归寻找 
			if(flag) return; 
			side.erase(it->second);	//删除刚刚的记录边
		}
	}	
}

void find_sides(int s,int d){ //初始化 flag、side,顺便分个模块出来 
	flag=false;
	side.clear(); //清空 map<int, int>side
	__sides(0,s,d);
}

int main(){ 
	int n,m;
	cin>>n>>m;	
	int xi,yi;
	for(int i=1; i<n; i++){
		cin>>xi>>yi;
		D[xi].maps[yi]=i;
		D[yi].maps[xi]=i; 
	}
	
	int ai,bi;	
	cin>>ai>>bi;          //第一个无序对(a1,b1) 
	find_sides(ai,bi);    //路径 
	map<int, int> same_side(side);  //目前就一条路,相同边就是该路径  
	
	for(int i=1; i<m; i++){	//剩下的 m-1 个无序对(ai,bi)
		cin>>ai>>bi;
		find_sides(ai,bi);   //结果路径保存到 map<int, int>side 里
				
		for(map<int, int>::iterator it = same_side.begin(); it!=same_side.end(); it++){ 							
 			//寻找相同边
			int side_i = it->first;
			if( side.find(side_i) == side.end() ){
				if(it==--same_side.end()){
					same_side.erase(it); //  不是共同边,删除 
					break; 
				}
				if(same_side.empty()){ //    没有相同边了,不满足条件,结束 
					cout<<"-1";
					return 0;
				} 							
			}
		}
	}
	cout<<(--same_side.end())->first<<endl; 
	return 0;
}

Guess you like

Origin blog.csdn.net/QENGFENG/article/details/130087304