新生训练_02

A - 构造最长递增子串

题意: 给定n个元素,你最多可以修改一个元素(可以为任意值)。问你严格递增的最大连续段。

解法一(别人的,我感觉比较牛):
因为要找的序列元素是连续的,所以可以正序dp求出以ai 结尾的最长递增子串,倒序dp求出以ai 开头的最长递增子串。
然后只需要从头到尾扫一遍,更改当前ai的值判断能不能使ai两边的串连起来(不能则舍掉一边),更新最大长度即可。
原来可以通过l[i]=l[i-1]+1;的这种方式求出以ai 开头或结尾的最长递增子串,然后max一下ans和前后两个子串长度和+1

解法二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
解法一:
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
const int N=100007;
int n,l[N],r[N],a[N],ans;
int main(){
	while(~scanf("%d",&n)){
		l[0]=r[0]=l[n+1]=r[n+1]=a[0]=a[n+1]=ans=0;
		for(int i=1;i<=n;i++)scanf("%d",&a[i]);
		for(int i=1;i<=n;i++)
			if(a[i]>a[i-1])l[i]=l[i-1]+1;
			else l[i]=1;
		for(int i=n;i;i--)
			if(a[i]<a[i+1])r[i]=r[i+1]+1;
			else r[i]=1; 
		for(int i=1;i<=n;i++)
			if(a[i+1]-a[i-1]>1)
				ans=max(ans,r[i+1]+l[i-1]+1);
			else 
				ans=max(ans,max(l[i-1]+1,r[i+1]+1));
		printf("%d\n",ans);
	}
}
B - Is it beautiful?

题目大意:

给一个排列,定义 m 为存在一段连续的 1~m 的排列(m为这段排列包含连续数的个数),如 {4,5,1,3,2,6} ,就存在l=3,r=5的一个区间{ 1,3,2 },为 m=3 的排列,但是就不存在 m=2 的排列(m=2就是有两个相连续的数)。问对于每一个 m 判断是否存在 1~m的一个排列。

思路:
只要将每一个数字的位置记录下来为 pos数组(pos数组的下标为这个数,数组的值为该排列的数的大小),例如 {4,5,1,3,2,6} 的 pos 数组就是 {3,5,4,1,2,6} 那么我们只要从前往后记录最大值 maxpos 和最小值 minpos ,然后 maxpos−minpos+1==i 就是存在 1~m 的排列。

upload successful

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
using namespace std;
int  pos[200001];
int main(){
    int t,n;
    cin>>t;
    int m;
    while(t--)
    {
        cin>>n;
        for (int i = 1; i <= n; i++){
            cin>>m;
            pos[m] = i;
        }
        int maxpos = 1;//为了第一次获得有效范围内的最大最小值要这么写 
        int minpos = n;
        for (int i = 1; i <= n; i++){
			//这是一个维护一个序列的最大最小值的有效方法
			//这要比写一个set或者重新排序或者
			//扫描一遍区间来维护区间的最大最小值要好很多 
            minpos = min(minpos, pos[i]);
            maxpos = max(maxpos, pos[i]);
            cout<<(maxpos-minpos+1==i?1:0);//代码的简洁性,可以把好几步和到一起 
        }
        cout<<endl;
    }
}
C - Juicer

不会ing、、、
题解blog:https://www.cnblogs.com/dongsheng/archive/2013/04/25/3043512.html
https://blog.csdn.net/weixin_30786617/article/details/97649147
https://blog.csdn.net/smile_benson/article/details/51458175
https://blog.csdn.net/qq_45530271/article/details/103809647

D - Eat Candies

题意
给你三堆糖果,每天可以同时吃两个不同颜色的,问最后最多吃多少天

解法一思路:
先把r,g,b排序,从小到大为a,b,c如果a+b<=c,结果肯定输出a+b
否则输出(a+b+c)/2
原因:为了使天数最多,每次取最多和次多的两堆糖果,当次多的糖果吃到与最少的糖果相等时,把最多的糖果平分到最少和次多那一堆,(如果最多的为奇数,那么总共还剩一个,如果为偶数,所有糖果用完),所以说最优解剩下的糖果不超过两个(a+b>c时).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
解法一:
#include<iostream>
#include<algorithm>
using namespace std;
int t=0;
int a[5];
int main()
{
   	cin>>t;
   	while(t--)
	{
		cin>>a[1]>>a[2]>>a[3];
		sort(a+1,a+4);		//从小到大排 
		if(a[3]>a[1]+a[2])
		cout<<a[1]+a[2]<<endl;
		else
		cout<<(a[1]+a[2]+a[3])/2<<endl;
	}
    return 0;
}

解法二(别人的思路):
//题意分析:q组数据,每组给定三个正数,每次从中选两个数减一,问最多经过几次使得这三个数中第一次出现0
#include <cstdio>
#include <algorithm>

using namespace std;

int main() {
    int q;
    scanf("%d", &q);
    while (q --) {
        int r, g, b;
        scanf("%d%d%d", &r, &g, &b);
        // 最小值,最大值,中间值
        // 思路就是将中间值分配到最小值和最大值上,使得这两个值的大小尽可能接近 
        int mi = min(r, min(g, b)), ma = max(r, max(g, b)), mid = r + g + b - mi - ma;
        if (mi + mid <= ma) mi += mid;
        else {
            int tmp = mi + mid - ma;
            mi += mid;
            mi -= tmp / 2 + tmp % 2;
            ma += tmp / 2;
        }
        printf("%d\n", mi);
    }
    return 0;
}

解法三:二分枚举 O(lgn)

为什么想到用二分呢?因为天数区间为[1, 1.5×10^8]. 一天吃两个糖果,最多可以有 3e8 个糖果. 因此最多可以吃 1.5e8 天。另外,我们假设糖果总数 n = 4. 如果是{4,0,0},最多能吃0天;{3,1,0},最多能吃1天;{2,1,1},最多能吃2天。也就是说,n = 4 对应的天数区间为[0,2]. 我们需要求最多天数,即求该区间的有边界。
因此,我们可以二分枚举天数,利用天数计算出当前天r,g,b能组成的最大糖果总数(tot),再与该天吃的糖果总数(mid×2)比较。

那么tot = min(mid,r) + min(mid,g) + min(mid,b). 因为在mid天每种糖果最多只能吃不超过mid个,并且糖果吃完后不能再吃。因此是min(mid,*).

如果 tot < mid2 意味着当前吃了mid天后糖果数不够,天数可能取多了,缩小右边界;
如果 tot >= mid
2 意味着mid天数合法,即可以吃到mid天,于是向右逼近,取最大的mid.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
using namespace std;

int main()
{
	int n;
	cin>>n;
	while(n--)
	{
		int r, g, b;
		scanf("%d%d%d",&r, &g, &b);
		int L = 0, R = 3e8+5;
		int ans = 0;
		while(L < R)
		{
			int mid = L+R>>1;
			int tot = min(mid,r) + min(mid,g) + min(mid,b);	
			if(mid*2 > tot)	
			{
				R = mid;
			}
			else if(mid*2 <= tot)
			{
				L = mid+1;
				ans = max(ans,mid);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
E - 由你来决定怎么颁奖

题意:有n个选手,解题数量为pi道(已经从大到小有序),让你从中选出金牌选手,银牌选手,铜牌选手的数量。要求金牌选手的数量小于银牌和铜牌的数量,对于银牌和铜牌的数量不做要求。并且g+s+b的数量不超过n的一半,且尽可能的最大。
给你t组测试,输出金牌 银牌 铜牌的数量,若不符合要求输出0 0 0

首先这一题让我知道了n个数据存到数组中,从下标1开始存有时候不见得比从0开始存要好,这一题就是这样,从1开始存就很麻烦,要注意下标和循环变量之间的差异,而从0开始存,就可以减少很多麻烦;
而且本题是一个多解题目,只要找到一个符合要求的解就好了(求这个解的方法要能求出其他的解才可以),所以按金牌数量最少的逻辑找到答案就是符合要求的解

tips:
向上取整: int a=ceil(2.2) //a=3
int j = ceil(-2.2) //a=2
向下取整: int i = floor(2.2); //a=2
四舍五入: double i = round(2.2);//i=2

本题的解法就是选出最少的金牌数,然后选出符合要求的最少银牌数这就是合适的划分点,剩下的都给铜牌,最后判断一下各类的数量是否都符合要求即可。
本来的想法是在1 2 2的基础上没加1就是加3个,然后求得金牌的最大数量,然后遍历金牌的数量,找到合适的答案,可是这样比较麻烦,做了半天没整出来(解法三)所以写代码要全想好了(实在不会了可以猜答案)再去实现,不然遇到一点问题实现不了就得半途而废了

upload successful

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
解法1
#include<iostream>
using namespace std;
const int maxn=1e6;
int p[maxn];
int main(){
	int t,n;
	int g=0,s=0,b=0;
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=0;i<n;i++){
			cin>>p[i];
		}
		for(g=0;g<n&&p[g]==p[0];g++){}	 
		for(s=g;(s<n&&p[s]==p[s-1])||s-g<=g;s++) {}
		for(b=s;(b<n&&p[b]==p[b-1])||b-s<=g;b++){}
		while(b<n/2){
			int temp_b=b;
			while(temp_b<n&&p[b]==p[temp_b]){
				temp_b++;
			}
			if(temp_b<=n/2)b=temp_b;//除号向下取整 
			else break;
		}
		if(g>=s-g||g>=b-s||b>n/2)cout<<"0 0 0"<<endl;
		else cout<<g<<" "<<s-g<<" "<<b-s<<endl;
	}
}

解法二:
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=1e6;
int p[maxn];
int main(){
	int t,n;
	int g=0,s=0,b=0;
	int k=2,j=0;
	bool is=true;
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>p[i];
		}
		for(g=0;g<=n&&p[g+1]==p[1];g++){}
		for(s=g+1;(s<=n&&p[s+1]==p[s])||s-g<=g;s++) {}
		for(b=s+1;(b<=n&&p[b+1]==p[b])||b-s<=g;b++){}
		b++;
		while(b<=(n/2+1)){
			int temp_b=b;
			while(temp_b<=n&&p[b]==p[temp_b]){
				temp_b++;
			}
			if(temp_b<=(n/2+1))b=temp_b;
			else break;
		}
		b--;
		if(g>=s-g||g>=b-s||b>n/2)cout<<"0 0 0"<<endl;
		else cout<<g<<" "<<s-g<<" "<<b-s<<endl;
	}
}
解法三(未实现):
#include<iostream>
using namespace std;
const int maxn=1e6;
int p[maxn];
int main(){
	int t,n;
	int g=0,s=0,b=0;
	int k=0,j=0;
	bool is=true;
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>p[i];
		}
		sort(p+1,p+n,greater<int>());
		if(n/2<5){
			cout<<"0 0 0"<<endl;
			continue;
		}
		int halfn=n/2;
		int maxg=(halfn-5)%3;
		//先判断n==10和11的情况,因为1 2 2全都+1 就是2 3 3,所以用来%3 
		if(n==10||n==11){
			for(j=1;j<n;j++){
				if(p[j]>p[j+1])break;//找到前后不相等的就跳出来 
			}
			g=j;
			for(j=g+g+1;j<n;j++){
				if(p[j]>p[j+1])break;
			}
			s=j-g;
			for(j=j+g+1;j<n;j++){
				if(j>n/2)is=false; 
				if(p[j]>p[j+1])break;
			} 
			b=j-g-s;
			if(g<s&&g<s&&is){
				cout<<g<<" "<<s<<" "<<b<<endl;	
			}else{
				cout<<"0 0 0"<<endl;
			}
			continue;	
		}
		
	 	for(int i=1;i<=halfn;i++){
	 		//从1开始往上增加金牌的数量,然后更新原来的
			 //然后找到符合要求的最后一个,输出 
		}
	}
}
F - XorXor

题意:
设f(i,j)=ai^ a(i+1)^ a(i+2)^ …^aj 。
求[f(1,1) ^ f(1,2) … f(1,n) ] ^ [f(2,2) ^ f(2,3) … f(2,n)] ^ [f(n,n)]

upload successful

tips:任何数异或它本身=0,任何数异或0是它本身,所以一个数自身异或奇数次是它本身,自身异或偶数次是0。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
解法一(数组下标从0开始):
#include<iostream>
using namespace std;
const int maxn=1e5+10;
int a[maxn];
int ans;
int temp;
int t,n;
int main(){
	//因为超时,写了sync都不行,只好换了scanf,然后过了 
	scanf("%d",&t);
	while(t--){
		ans=temp=0;
		scanf("%d",&n);
		for(int i=0;i<n;i++){
			scanf("%d",&a[i]);
			//因为第一次提交超时,所以把输入和求k1放在一个循环里 
			if((n-i)%2==1)temp^=a[i];  //如果a[i]出现奇数次就异或上 
		}
		ans=temp;//此时ans为k1 
		for(int j=0;j<=n-2;j++){
			if((n-j)%2==1)temp^=a[j];//执行完后temp为k2,然后依次执行求k3,k4、、、kn 
			ans^=temp;//依次求k1^k2^k3...^kn 
		}
		printf("%d\n",ans);
	}
}
解法二(数组下标从1开始,别人思路):
/*所以假设k1=[f(1,1) ^ f(1,2) … f(1,n) ],其中a[1]是被异或了(n-1+1)次
那么k2=[f(2,2) ^ f(2,3) … f(2,n)] ,只需要把k1异或的(n-1+1)次a[1]异或掉就是k2。
同理k3=k2异或(n-2+1)次a[2],k4=k3异或(n-3+1)次a[3] …
最终答案就是k1到kn的异或和。
*/
#include<iostream>
#include<cstdio>
using namespace std;
const int N=100007;
int a[N],ans,now,n,t;

int main(){
	cin>>t;
	while(t--){
		cin>>n;
		now=ans=0;
		for(int i=1;i<=n;i++){
			scanf("%d",&a[i]);
			if((n-i+1)%2)now^=a[i];
		}
		for(int i=1;i<=n;i++){
			ans^=now; 
			if((n-i+1)%2)now^=a[i];
		}
		cout<<ans<<endl;
	}
}
G - 0011

看到梁sir说的括号匹配,好像是呀,0就是(,1就是);还可以把本题抽象成两个相对的元素a,b之类的,满足条件的可以用该种方法来解题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
错误解法1(双指针扫描):
#include<iostream>
#include<string>
using namespace std;

int main(){
	/*
	这种方法在判断01001101 类型(即数列中间为001101的情况,两个指针同时指向0)时就无法正确判断了,所以双指针扫一遍很难判断出来01的插入结果 
    后来改进为找到离末尾最近的相配对的1的位置,不能实现
	*/
	bool ans;
	int ptr1,ptr2;
	string s; 
	int num;
	cin>>num;
	while(num--){
		ans=true;
		cin>>s;
		ptr1=0;
		ptr2=s.length()-1;
		if(s[ptr1]!='0'||s[ptr2]!='1'||(s.length()%2!=0)){
			//当时在这个地方写为ptr2%2==0,是不对的,因为ptr2=length-1了 
			cout<<"NO"<<endl;
			continue; 
		}
		while(true){
			ptr1++;
			ptr2--;
			if(ptr1>ptr2)break;
			if(s[ptr1]=='1'){
				ptr2++;
				ptr1++;
			}
			if(!(s[ptr1]=='0'&&s[ptr2]=='1'))
			{
				ans=false;
				break; 
			}
		}
		if(ans)cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	} 
} 
正确解法2:
/*
统计0和1的个数,这个数列的性质是当前位置前的1的个数小于等于0的个数,yes的情况只有当最后扫描一遍之后且0和1的数量相同
*/
#include<iostream>
#include<string.h>
#include<string>
using namespace std;
int main(){
	int n;
	int num0=0,num1=0;
	string s;
	int i;
	cin>>n;
	while(n--){
		cin>>s;
		for(i=0;i<s.length();i++){
			if(s[i]=='0')num0++;
			else num1++;
			if(num1>num0){
				cout<<"NO"<<endl;
				break;
			}
		}
        //注意yes的条件,要想好,从多方面切入
		if(i==s.length()&&num0==num1)cout<<"YES"<<endl;
		num0=0;num1=0;
	}
}
H - Perfect String

题意:给出一个由abc和?构成的字符串,问号可替换为a,b,c(至少有一个问号),如果替换后的字符串相邻的两个字符都不相同,则称为完美字符串(符合要求),就输出该字符串,若无法形成完美字符串,则输出-1

要想到比较和替换问号左右的字符使之不相同就可以了,直接扫一遍就好了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
解法一:
#include<iostream>
using namespace std;
int main(){
	int t,n,i;
	string s;
	cin>>t;
	while(t--){
		int flag=0;
		cin>>s;
		for(i=0;i<s.length();i++){
			if(s[i]=='?'){
				if(i!=0)
					s[i]=(s[i-1]-'a'+1)%3+'a';//如a的后面补b 
				else
					s[i]='a';
				if(s[i+1]!='?')
					if(s[i]==s[i+1])//若补b后面的问号也为b,则补c就可以了 
						s[i]=(s[i+1]-'a'+1)%3+'a';
			}
		}
		for(i=0;i<s.length();i++){//char数组要用strlen(a)才可以  
			if(s[i]==s[i+1]){
			
				flag=1;
				break;
			}
		}
		if(flag)
			cout<<"-1"<<endl;
		else
			cout<<s<<endl;
	}
	return 0;
}
解法二(梁sir):
#include<iostream>
#include<string.h>
#include<cstdio>
using namespace std;
int t,f;
string s;
int main(){
	cin>>t;
	while(t--){
		cin>>s;
		f=1;
		for(int i=0;i<s.length();i++){
			if(s[i]=='?'){
				if(i==0){
					if(s[i]!='a'&&s[1]!='a')s[i]='a';else
					if(s[i]!='b'&&s[1]!='b')s[i]='b';else
					if(s[i]!='c'&&s[1]!='c')s[i]='c';
				}else {
					if(s[i+1]!='a'&&s[i-1]!='a')s[i]='a';else
					if(s[i+1]!='b'&&s[i-1]!='b')s[i]='b';else
					if(s[i+1]!='c'&&s[i-1]!='c')s[i]='c';
				}
			}else if(s[i]==s[i+1]){	
			//其实可以直接在这里判断是否符合要求 
			//若果第i位的非?字符和后面的字符相等,就不合要求 
				f=0;	break;
			}
		}
		if(f)cout<<s<<"\n";else printf("-1\n");
	}
}
I - 十进制中的二进制

注意:(一定要注意题意)本题在提交的时候要输入多组数据,并没有说先输入case的数量t,所以直接while(cin>>n)或者!=eof即可

upload successful

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
解法一:
#include<iostream>
#include<string>
using namespace std;
//cnt用来遍历这个十位数的长度,因为到10^9,所以大于10的话就可以return了
//tmp代表这一次用来判断的数,ans记录符合要求的个数
int ans=0;int n;
void dfs(int tmp,int cnt){
	if(tmp>n)return;
		if(cnt>10)return ;
		if(tmp<=n)ans++;
		dfs(tmp*10,cnt+1);
		dfs(tmp*10+1,cnt+1);
}
int main(){
	while(cin>>n){
		dfs(1,1 );//从十位数的1开始,从十位数的个数1开始dfs
		cout<<ans<<endl;
		ans=0;
	}
}
解法二(别人的):
#include<iostream>
using namespace std;
typedef long long ll;
ll dfs(ll x){
	if(x==0)return 0;
	if(x==1)return 1;
	return dfs(x>>1)*10+(x&1); 
}
int main(){
	int n;
	while(cin>>n){
		ll ans=1,cnt=0;
		while(ans<=n){
			cnt++;
			ans=dfs(cnt);
			//验证小于n的所有数的二进制表示
		}
		cout<<cnt-1<<endl;
	}
}
解法三(别人的):
#include<iostream>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int n,ans;
void dfs(int v,int d){
	if(!d){
		if(v<=n&&v)ans++;
		return;
	}
	dfs(v*10,d-1);
	dfs(v*10+1,d-1);
}
int main(){
	while(~scanf("%d",&n)){
		ans=0;
		dfs(0,10);//dfs,用0和1填10位数,造出来的数小于n结果就++
		printf("%d\n",ans);
	}
}
解法四(于sir):
#include<iostream>
using namespace std;
long long n;
long long sum;
int a[2]={0,1};

void zhao(long long x){
	if(x>n){
		return;
	}
    else{
		sum++;
		for(int i=0;i<2;i++){
			zhao(x*10+a[i]);
		}
	}
}
int main()
{
    
	while(cin>>n){
		sum=0;
		zhao(1);
		cout<<sum<<endl;
	}
	
}
[J-新年快乐](https://vjudge.net/problem/279484/origin)

upload successful

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//分情况讨论即可
#include<iostream>
#include<stdio.h>
#include<math.h>
using namespace std;
int main() {
	int x,y,z,t;
	double ans=0.0;
	while(cin>>x>>y>>z>>t){
		if((y==0&&z==0)||(z-x)==0){
			printf("0.0\n");
		}else{
			if(y==0){
				ans=1.0/2*abs(z-x)*t;
				printf("%.1lf\n",ans);
			}else if(z==0){
				ans=1.0/2*abs(z-x)*t;
				printf("%.1lf\n",ans);//注意printf中回车是反斜杠n 
				//continue;因为if-else语句就只执行一个语句块,所以可以不用加continue 
			}else{
				ans=1.0/2*abs(z-x)*(y+t);
				printf("%.1lf\n",ans);
			}
		}
	}
}
解法二(梁sir):
//卧槽,原来这题这么简单;要找那几种情况的共性(本质就是求梯形面积)
#include <cstdio>
#include <cmath>
using namespace std;
int main()
{
    double x,y,z,t;
    while(~scanf("%lf%lf%lf%lf",&x,&y,&z,&t))
    printf("%.1lf\n",(fabs(y)+fabs(t))*fabs(x-z)/2);
    //高为z-x,上底看做y(当y或t为0的时候就为三角形,但是为0了加上就不影响最终结果了),下底看做t。
}

tips:
abs函数(在math.h中):函数原型为int abs(int n);
fabs函数(在math.h中):函数原型为double fabs(double x);
祥见连接C 标准库 - <math.h>
另外pow用来处理double类型的数 double pow(double x, double y)
long类型 scanf(“%ld”,&n)!=EOF
long long类型 scanf(“%lld”,&n)!=EOF

一、总结:
1、首先这一次知道了代码简洁这东西,感觉自己写的太繁琐了(那个j题,求梯形面积,我却给分了好多情况才写好),比如求同样是实现一个步骤,别人可以一步完成,而自己却要绕好几步,想了想代码简洁还是建立在看过很多代码,思路明确的基础上的,所以要多刷题
2、知道了一个求最长递增子串的方法,先正着来一遍,在倒着来一遍,然后ans=max(ans,max(l[i-1]+1,r[i+1]+1)); 这种方法太奇妙了,想了想,其实也很符合常规思路,要找最长的,找隔一个的前后两个最长的连在一起就好了。
3、做不出来的题,不要自己一直闷着想,给自己一个期限,如1.30小时,做不出来看看别人思路;对哦,要写完了自己的题解之后多看看别人的题解,然后找到他们的长处(如简洁,思路巧妙,效率高)然后想想他们的思维,改变自己的思维方式。取他人之长补己之短。
4、另一个要好好读题,比如i题那个多组输入,其实是放在while(cin>>n)这种形式,而不是输入组数的那种方式。而且英文的题意有时候很难弄懂,要坚持读,理解
5、D题告诉 我不会的(还有0101这题,a???cb这题),要从多组数据中找到规律,然后有依据的假设,并进行验证。这题答案为(a[1]+a[2]+a[3])/2,可以从多组数据中进行找规律,猜测。
6、写代码要一下子想好所有的解决方案,比如维护最大值,最小值(通过set维护,或者sort,或者),不要因为一时没想好,开始写后又被卡住了。

  • 代办
    • 最长递增子序列 lis lcs什么东西的
    • a题和c题有时间在重新理解一下

二、做题遇到的英文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
consecutive 	连续不断的
is legal 	是否是符合要求的
characters		n.特性;人物角色(character复数)v.描述(character的三单形式);表示…的特性
restriction		n.限制;约束;束缚
respectively     adv.分别地;各自地,独自地
contest    竞争 比赛
Regional	adj.(regional)地区的,区域的;局部的;整个大地区的
standings	n.战绩(standing的复数);名次表
participant		n.参与者,参加者 adj.参与的
jury	裁判 判断
positive number		n.[数]正数
Xor		异或;异或门;按位异或;逻辑异或;运算符
permutation		n.[数]排列;[数]置换
indices		n.指数;目录(index的复数)such that the numbers [pl,pl+1,…,pr]
determine	v.(使)下决心,(使)做出决定vt.决定,确定;判定,判决;限定   vi.确定;决定;判决,终止;[主用于法律]了结,终止,结束
It is guaranteed	约定
exceed 	超出某个范围
subsegment of the sequence a   意为a的一个子串
at most		至多

三、0x3f3f3f3f的介绍:
  0x3f3f3f3f的十进制是1061109567,是10^9级别的(和0x7fffffff一个数量级),而一般场合下的数据都是小于10^9的,所以它可以作为无穷大使用而不致出现数据大于无穷大的情形。
  另一方面,由于一般的数据都不会大于10^9,所以当我们把无穷大加上一个数据时,它并不会溢出(这就满足了“无穷大加一个有穷的数依然是无穷大”,而0x7fffffff不能满足“无穷大加一个有穷的数依然是无穷大”这个条件,它会变成了一个很小的负数。),事实上0x3f3f3f3f+0x3f3f3f3f=2122219134,这非常大但却没有超过32-bit int的表示范围,所以0x3f3f3f3f还满足了我们“无穷大加无穷大还是无穷大”的需求。
  0x3f3f3f3f还能给我们带来一个意想不到的额外好处:
如果我们想要将某个数组清零,我们通常会使用memset(a,0,sizeof(a)),方便又高效,但是当我们想将某个数组全部赋值为无穷大时,就不能使用memset函数而得自己写循环了,因为memset是按字节操作的,它能够对数组清零是因为0的每个字节都是0(一般我们只有赋值为-1和0的时候才使用它)。现在好了,如果我们将无穷大设为0x3f3f3f3f,那么奇迹就发生了,0x3f3f3f3f的每个字节都是0x3f!所以要把一段内存全部置为无穷大,我们只需要memset(a,0x3f,sizeof(a))。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值