新生训练class 1- 熟悉oj的使用方法&&贪心

  • Calculate a+b
1
2
3
4
5
6
7
8
9
10
#include <iostream>
using namespace std;

int main()
{
    int a,b;
    cin >> a >> b;
    cout << a+b << endl;
    return 0;
}
  • B ASCII码排序(输入三个字符后,按各字符的ASCII码从小到大的顺序输出这三个字符。 )
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
#include<iostream>
#include<algorithm> //sort函数  时间复杂度为 n*log2n 
using namespace std;
const int maxn=3;
struct ascii{
	char zi;
//	ascii(char a,char b,char c):a(a),b(b),c(c){}  如果有多个数的话,可以用构造函数来赋值 
}asc[maxn];
bool cmp(ascii x, ascii y){
	return (int )x.zi<(int)y.zi;
} 

int main(){
	//方法一: 
	char a,b,c;
	char tmp;
	//这种方法三个if,各个if之间可以相互调换顺序 
	//比较的逻辑是a>b,a>c,b>c;这样就实现了大的往后排 
	while((cin>>a>>b>>c)){
		
		if((int)a>(int)b){
			tmp=a;
			a=b;
			b=tmp;
		}
		if((int)a>(int)c){
			tmp=a;
			a=c;
			c=tmp;
		}
		if((int )b>(int )c){
			tmp=b;
			b=c;
			c=tmp;
			
		}
		cout<<a<<" "<<b<<" "<<c<<endl;
		//cout<<"\n";这样要比cout<<endl;要快 
	}


	//方法二:sort(a,a+3);这样写可以对一个char类型的char数组按ascii码进行排序 
	
	//方法三,利用结构体排序: 
	while(cin>>asc[0].zi>>asc[1].zi>>asc[2].zi){
		sort(asc,asc+3,cmp);
		for(int i=0;i<3;i++){
			if(i==2)cout<<asc[i].zi<<endl;
			else cout<<asc[i].zi<<" ";
		}
	}
	
	
}
  • C 计算两点间的距离 (输入两点坐标(X1,Y1),(X2,Y2),计算并输出两点间的距离。 )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<iostream>
#include<math.h>
#include <iomanip> 
using namespace std;
//c语言版 
//编写时scanf写为scanf("%lf,%lf,%lf,%lf",x1,x2,y1,y2); ,一直出错 
//int main(){
//	float  x1,x2,y1,y2;
//	while(~scanf("%f%f%f%f",&x1,&y1,&x2,&y2)){
//	printf("%.2f\n",sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)));
//	}
//} 

//c++版本
int main(){
	//切断cin和cout的联系,加快速度 
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	
	double x1,x2,y1,y2;
	while(cin>>x1>>y1>>x2>>y2){
		cout<<setprecision(2)<<fixed<<sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))<<endl;
	}
}
  • D - 计算球体积(根据输入的半径值,计算球的体积。 )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include<math.h>
#include <iomanip> 
using namespace std;
#define PI 3.1415927
int main(){
	//切断cin和cout的联系,加快速度 
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	
	double r;
	while(cin>>r){
		cout<<setprecision(3)<<fixed<<4*PI*pow(r,3)/3<<endl;
//		cout<<setprecision(3)<<fixed<<(4/3)*PI*pow(r,3)<<endl;
//上面这样的结果是不对的,应该乘完了之后在去除 
//		cout<<setprecision(3)<<fixed<<4*PI*r*r*r/3<<endl;
	}
}
  • E - 求绝对值(求实数的绝对值。 )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<iostream>
#include<math.h>
#include <iomanip> 
using namespace std;
int main(){
	//切断cin和cout的联系,加快速度 
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	
	double r;
	while(cin>>r){
		if(r<0){
			//cout<<setprecision(2)<<fixed<<r*(-1)<<endl;  这两种方法都可以 
			cout<<setprecision(2)<<fixed<<-r<<endl;
		}
		else{
			cout<<setprecision(2)<<fixed<<r<<endl;
		}
	}
}
  • F - 成绩转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<iostream>
#include<math.h>
#include <iomanip> 
using namespace std;
#define PI 3.1415927
int main(){
	//切断cin和cout的联系,加快速度 
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	int n;
	while(cin>>n){
		if(90<=n&&n<=100 )cout<<"A"<<endl;
		else if(80<=n&&n<=89)cout<<"B"<<endl;
		else if(70<=n&&n<=79)cout<<"C"<<endl;
		else if(60<=n&&n<=69)cout<<"D"<<endl;
		else if(0<=n&&n<=59)cout<<"E"<<endl;
		else cout<<"Score is error!"<<endl;
	}
}
  • G - 第几天?(给定一个日期,输出这个日期是该年的第几天。 )
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

#include<iostream>
using namespace std;
bool isLeapYear(int y) {
    return (y % 4 == 0 && y % 100 != 0) || (y % 400 == 0);
}
int main(){
	int m,d,y,tianshu;
	int rn[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};
	int pn[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
	//格式化输入,%d/%d/%d这样才可以 
	while(~scanf("%d/%d/%d",&y,&m,&d)){
		//~scanf("%d%c%d%c%d",&y,&ch,&m,&ch,&d)这种方法也是可以的 
		tianshu=0; //在这地方一定要重新初始化,不然tianshu会加上上一次运算的值 
		if(isLeapYear(y)){
			for(int i=1;i<m;i++){  //从1月加到第m-1个月 
				tianshu +=rn[i];
			}
			tianshu+=d;
		} else{
			for(int j=1;j<m;j++){
				tianshu +=pn[j];
			}
			tianshu+=d;
		}
		cout<<tianshu<<endl;	
	}
}
  • H - 平方和与立方和(给定一段连续的整数,求出他们中所有偶数的平方和以及所有奇数的立方和。 )
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
#include<iostream>
using namespace std;

int main(){
	int m,n,jishu,oshu;
	while((cin>>m>>n)){
		jishu=0;oshu=0;
		if(n<m){
			//可以用swap(n,m)来交换n和m的值 
			for(int i=n;i<=m;i++)
				if(i&1==1){//是奇数
					jishu+=i*i*i;		
				}else{
					oshu+=i*i;
				}	
		}else{
			for(int i=m;i<=n;i++)
				if(i&1==1){//是奇数
					jishu+=i*i*i;		
				}else{
					oshu+=i*i;
				}
		}
		cout<<oshu<<" "<<jishu<<endl; 
			
	}
	
}
  • I - 数值统计(统计给定的n个数中,负数、零和正数的个数。 )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
using namespace std;
int n;
double shu[101];
int ling,zhengshu,fushu;
int main(){
	//输入n并且!0时的语句为下面的这条语句 
	while(cin>>n,n!=0){
		ling=zhengshu=fushu=0; 
		for(int i=0;i<n;i++)cin>>shu[i];
		for(int i=0;i<n;i++){
			if(shu[i]>0)zhengshu++;
			else if(shu[i]<0)fushu++;
			else ling++;
		}
		cout<<fushu<<" "<<ling<<" "<<zhengshu<<endl;
	} 
}
  • J - 求数列的和(数列的第一项为n,以后各项为前一项的平方根,求数列的前m项的和。 )
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
#include<iostream>
#include<math.h>
#include <iomanip> 
using namespace std;

int main(){
	int n,m;
	double sum=0,tmp;
	while(cin>>n>>m){
		sum=0;
		if(m==1){
			cout<<setprecision(2)<<fixed<<n<<endl;
		}else{
			sum+=n;
			tmp=n;
			for(int i=1;i<m;i++){//m-1项 
				sum+=sqrt(tmp);
				tmp=sqrt(tmp);
			}
			cout<<setprecision(2)<<fixed<<sum<<endl;	
		}
		
		
	}
}
  • K - 水仙花数
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
#include<iostream>
#include<string.h>
using namespace std;

int shiwei(int shu){
	return ((shu/10)%10); 
}
int baiwei(int shu){
	return ((shu/100)%10);
}

int main(){
	int xia;
	int m,n;
	int a[1000];
	int flag;
	while(cin>>m>>n){
		memset(a,0,sizeof(a));
		xia=0;
		flag=0;//这地方以为内下一次循环要用到这些变量,
		//所以要对一些变量初始化才可以不会出错 
		for(int i=m;i<=n;i++){
			if(i==((i%10)*(i%10)*(i%10)+shiwei(i)*shiwei(i)*shiwei(i)+baiwei(i)*baiwei(i)*baiwei(i)))
			{
				flag=1;
				xia++;
				a[xia]=i;
				
			}
		}
		
		if(flag==0){
			cout<<"no"<<endl;
			
		}else{
			for(int i=1;i<=xia;i++){
				if(i==xia)cout<<a[i]<<endl;
				else{
					cout<<a[i]<<" ";
				}
			}
				
		}
	}
}
  • L - 多项式求和 (1 - 1/2 + 1/3 - 1/4 + 1/5 - 1/6 + …现在请你求出该多项式的前n项的和。 )
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
#include<iostream>
#include<math.h>
#include <iomanip> 
using namespace std;

double duo(int n){
	double sum=0.00;
	for(int i=1;i<=n;i++){
		if(i%2==1)sum=sum+1.0/i;
		else sum=sum-1.0/i;
	}
	return sum;
}
int main(){
	
	int m;
	int a[110];//不能在cin>>m之后写a[m] 
	cin>>m;
	
	for(int i=0;i<m;i++)cin>>a[i]; 
	for(int i=0;i<m;i++){
		printf("%.2lf\n",duo(a[i]) );
	}
	
}
  • M - 素数判定(对于表达式n^2+n+41,当n在(x,y)范围内取整数值时(包括x,y)(-39<=x<y<=50),判定该表达式的值是否都为素数。 )
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
#include<iostream>
#include<string.h> 
using namespace std;

const int maxn=20000;
int prime[maxn];
bool isPrime[maxn];
bool noPrime[maxn];
//2591
//1523
int eulerSieve_1(int n){
	int num=0;
	memset(isPrime,true,sizeof(isPrime));
	isPrime[0]=isPrime[1]=false;
	for(int i=2;i<=n;i++){
		//这个从prime的0下标开始存素数 
		if(isPrime[i])prime[num++]=i;
		//第一次执行num++,prime[0]存入i,之后num为1,那么下面这个for中num为1 
		for(int j=0;j<num&&i*prime[j]<=n;j++){
			//这个从j开始到num,遍历一遍prime数组,所以遍历的次数为数组个数 
			isPrime[i*prime[j]]=false;
			if(i%prime[j]==0)break;
		}
	}
	return num;
}
int sieve(int n){
	int num=0;
	memset(isPrime,true,sizeof(isPrime));
	isPrime[0]=isPrime[1]=false;
	for(int i=2;i<=n;i++){
		if(isPrime[i]){
			prime[num++]=i;
			for(int j=2;j*i<=n;j++){
				isPrime[j*i]=false;
			}
		}
	}
	return num;
}

int eulerSieve_3(int n){
	int num=0;
	memset(prime,0,sizeof(prime));
	memset(noPrime,false,sizeof(noPrime));
	noPrime[0]=noPrime[1]=true;
	for(int i=2;i<=n;++i){
		if(noPrime[i]==false)prime[++num]=i;
		//从1开始存素数 
		for(int j=1;j<=num&&i*prime[j]<=n;++j){
			noPrime[i*prime[j]]=true;
			if(i%prime[j] ==0)break;
		}
	} 
	return num;
}

int main()
{
	int x,y,flag=0;
	int tmp;
	sieve(20000);
	//for(int i=0;i<100;i++) cout<<prime[i]<<" ";
	while(cin>>x>>y){
		if(x==0&&y==0)break;
		flag=0;
		for(int i=x;i<=y;i++){
			tmp=i*i+i+41;
			if(noPrime[tmp]==true){
				//但是这一句写为了isPrime[tmp]==false就会出现错误,不知道为什么 
				flag=1;
				break;
			}
		}
		if(flag==0)cout<<"OK"<<endl;
		else cout<<"Sorry"<<endl;
		
	}
}
  • N - 蟠桃记 (第一天悟空吃掉桃子总数一半多一个,第二天又将剩下的桃子吃掉一半多一个,以后每天吃掉前一天剩下的一半多一个,到第n天准备吃的时候只剩下一个桃子。聪明的你,请帮悟空算一下,他第一天开始吃的时候桃子一共有多少个呢? )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include<iostream>
using namespace std;

int digui(int n){
	if(n==1)return 1;
	else return  2*(digui(n-1)+1);
}

int main(){
//一定要把main写对了,写成mian就会出现id已存在的错误 
	int n;
    while(cin>>n){
    	cout<<digui(n)<<endl;
	}
}
  • O - 青年歌手大奖赛_评委会打分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<iostream>
#include<algorithm>
using namespace std;

const int maxn=110;
int main(){
	int n;
	double sum;
	int a[maxn];
    while(cin>>n){
    	sum=0;
    	for(int i=0;i<n;i++)cin>>a[i];
    	sort(a,a+n);
    	for(int i=1;i<n-1;i++)sum+=a[i];
    	printf("%.2lf\n",sum/(n-2));
	}
}
  • P-Best Cow Line (字典序问题)
    可以用cin.getline();但是时间慢, 也可以用 scanf(“%s”, tmp);s[i] = tmp[0];

参考了网上的思路发现,还可以用scanf(“ %c”, &ch);

在格式串中,空格的意思是匹配输入中的所有换行、TAB、空格,所以加上一个空格,就可以屏蔽掉在输入中的所有的不愉快的因素了。

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
#include <stdio.h>
#include <string.h>
char s[2002];
int main(){
int n;
	while(scanf("%d",&n)!=EOF)
	{
		for(int i=0;i<n;i++){
			scanf(" %c",&s[i]);	//前面的空格用来匹配空白符号 
		}
		
		int a=0,b=n-1;
		int ans=0;
		while(a<=b){
			bool left=false;		
			for(int i=0;a+i<=b;i++){		//字符串反转比较, 
				if(s[a+i]<s[b-i]){
					left=true;
					break;
				}
				else if(s[a+i]>s[b-i]){
					left=false;
					break;
				}
			}
			if(left)  putchar(s[a++]);
			else putchar(s[b--]);   //如果相等就返回字符串右边的
			ans++;
			if(ans==80){
				printf("\n");
				ans=0;
			} 	
		}	
		  printf("\n");	
	}
	return 0;
}
  • Q Saruman’s Army
      题意:在一条直线上,有n个点。从这n个点中选择若干个,给他们加上标记。对于每一个点,其距离为R以内的区域里必须有一个被标记的点。问至少要有多少点被加上标记。
      题解:我们从最左边的开始考虑。对于这个点,到距其R以内的区域必须要有带有标记的点。带有标记的点一定在其右侧(包含这个点本身)。给从最左边开始,距离为R以内的最远的点加上标记,尽可能的覆盖更靠右边的点。对于添加了标记的点右侧相距超过R的下一个点,采用同样的方法找到最右侧R距离以内最远的点添加标记。在所有点都被覆盖之前不断重复这一过程。
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
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[1010];
int main()
{
	int n,R,i,ans;
	while(scanf("%d%d",&R,&n)&&R!=-1||n!=-1)
	{
		for(i=0;i<n;++i)
			scanf("%d",&a[i]);
		sort(a,a+n);
		i=0;ans=0;
		while(i<n)
		{
			int s=a[i++];//s表示没有被覆盖的最左边的点 
			while(i<n&&a[i]<=s+R)//一直向右前进直到距s的距离大于R的点 
				i++;
			int p=a[i-1];//被标记的点 
			while(i<n&&a[i]<=p+R)//一直向右前进直到距p的距离大于R的点 
				i++;
			ans++;
		}
		printf("%d\n",ans);
	}
	return 0;
}
  • R - Fence Repair
    每次都要先从大长木板上切下要分割的木板中的较大的小木板,这样才能最后切割的费用最小。
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
#include<stdio.h>
#include<iostream>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
	priority_queue<long long,vector<long long int>,greater<long long int> >p;
//逆着来,就找两个最小的,然后压进去,倒这来求
	long long int i,n,a,s,x,y;
	scanf("%lld",&n);
		s=0;
	   for(i=0;i<n;i++)
	   {
		   scanf("%lld",&a);
		   p.push(a);
	   }
	   while(p.size()>1)
	   {
	    	x=p.top();
		    p.pop();
		    y=p.top();
		    p.pop();
		    s=s+x+y;
		   
		    p.push(x+y);
	    }
	    printf("%lld\n",s);
	   
	return 0;
}
  • S - Cleaning Shifts
    题意:给出区间[ 1,T ]和N个小区间,要求用尽可能少的小区间覆盖区间[ 1,T ],输出最少的小区间数量;若不能覆盖,输出-1。

思路:贪心。

具体:令begin为当前未被覆盖的区间起点。

贪心策略:选取包含点begin的区间中右端点最大的那个;若不存在包含begin的区间,输出-1。

证明:因为begin为未被覆盖的区间起点,所以begin一定要被小区间覆盖,将最优解中覆盖begin的小区间命名为区间X。

以下使用剪贴技术证明。

若存在包含begin的小区间Y( Y != X )使最终所需的小区间数少于原最优解,那么Y一定包含了X之后的某些小区间,

即Y的右端点大于X的右端点,与贪心策略矛盾,得证。
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
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=25010;
int n, T, sum, start=1, end;
struct node{ int s, e; }cow[N];
 
bool cmp( node a, node b ) {
	return a.s<b.s;
}
 
int main() {
	scanf( "%d%d", &n, &T );
	for( int i=1; i<=n; i++ ) {
		scanf( "%d%d", &cow[i].s, &cow[i].e );
		end=max( end, cow[i].e );
		cow[i].e++;
	}
	sort( cow+1, cow+n+1, cmp );
	if( 1<cow[1].s || end<T ){ printf( "-1\n" ); return 0; }
	end=0;
	for( int i=1; i<=n; ) {
		bool flg=0;
		while( i<=n && cow[i].s<=start ) {
			end=max( end, cow[i].e );
			i++; flg=1;
		}
		if( !flg ){ printf( "-1\n" ); return 0; }
		sum++;
		if( end>T ) break;
		start=end;
	}
	printf( "%d\n", sum );
	return 0;
}
  • T poj3190Stall Reservations(贪心+优先队列)
    思路:
    首先根据挤奶时间的先后顺序排序。。。然后将第一头牛加入优先队列。。然后就是加入优先队列的牛应该根据越早结束挤奶那么优先级更高,如果时间结束点相等,那么开始时间早的优先级高。。。
    然后从前向后枚举。如果碰到有牛的挤奶时间的开始值大于优先队列的首部的结束值,那么说明这两头牛可以一起公用一个挤奶房。。然后从优先队列中删除这头牛。。那么这个问题就得到解决了。。。
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
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<limits.h>
#include<queue>
using namespace std;
const int maxn=1000000+10;
struct node{
    int st,ed;
    int pos;//pos记录是第几个奶牛
    bool operator<(const node &a)const
    {
        if(ed==a.ed)
           return st>a.st;
        return ed>a.ed;
    }
}a[maxn];
int used[maxn];//used记录奶牛挤奶的位置=。=
int cmp(node l1,node l2)
{
    if(l1.st==l2.st)
        return l1.ed<l2.ed;
    return l1.st<l2.st;
}
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        priority_queue<node>q;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&a[i].st,&a[i].ed);
            a[i].pos=i;
        }
        sort(a+1,a+n+1,cmp);
        q.push(a[1]);
        int ans=1;
        used[a[1].pos]=1;
        for(int i=2;i<=n;i++)
        {
            if(!q.empty()&&q.top().ed<a[i].st)//判定是否符合条件
            {
                used[a[i].pos]=used[q.top().pos];
                q.pop();
            }
            else//不符合条件槽的数量加一,同时这个奶牛应该在新加的槽
            {
                ans++;
                used[a[i].pos]=ans;
            }
            q.push(a[i]);
        }
        printf("%d\n",ans);
        for(int i=1;i<=n;i++)
            printf("%d\n",used[i]);
    }
    return 0;
}
  • U POJ 1017 Packets(贪心

题意:工厂出售边长分别为1,2,3,4,5,6的正方形板子,但工厂只有66的板子,其他的板子都是从这种板子上裁剪而来的。现在给出分别这些板子的需求量,问最少需要多少块66的板子。

题解:从面积大的开始取,一块66的板子可以去一块55的板子剩下11个 11的板子。取一块44的板子剩下5个22的板子。 66的板子可以取四块33的板子,在一块66板子上取33的板子数目为 1 2 3 4 的时候剩下 22的板子分别为 5 3 1 0,剩余部分还可以去11的板子。 若22的板子有剩余,还可以分割成1*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
#include<cstdio>
#include<cstring>
int dir[4]={0,5,3,1};
int a[10];
int main()
{
	int i,sum,ans;
	while(1)
	{
		sum=0;
		for(i=1;i<7;++i)
		{
			scanf("%d",&a[i]);
			sum+=a[i];
		}
		if(!sum)
			break;
		ans=a[6]+a[5]+a[4]+(a[3]+3)/4;//计算边长为3 4 5 6的板子消耗量 
		int cnt_2=a[4]*5+dir[a[3]%4];
		if(a[2]>cnt_2)
			ans+=(a[2]-cnt_2+8)/9;//当上面剩余的2*2板子量不足时,需要消耗新的板子 
		int cnt_1=ans*36-a[6]*36-a[5]*25-a[4]*16-a[3]*9-a[2]*4;
		if(a[1]>cnt_1)//当上面剩余的1*1板子量不足时,需要消耗新的板子 
			ans+=(a[1]-cnt_1+35)/36;
		printf("%d\n",ans);
	}
	return 0;
}
  • V Stripies (和R题Fence Repair是一样一样的)
    题意:介绍了一大堆,全废话。 题目就是说有n个物品,每个物品重w_i,对于两个物品他们合并时重量就会变成
    w = 2 sqrt(w_a w_b)。 问当n个物品合成一个时,最小重量是多少?
    题解:贪心啊,不过要用到一点数学知识,在n个物品中取两个物品合并,要想最后总重最小,要每次取两个重量最大的物品。关于这个结论,下面给出证明:
    设:n=3,三个物品的重量分比为:a,b,c, 合并之后最小重量为w。
    则w = 2 sqrt( a 2 sqrt(b c) )
    化简后的 w^2/8 = sqrt( aab*c ), 此式可得 a 取最小时 w 的值最小。
    归纳总结,n个物品每次取最大的两个合并,总重最小。
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
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
int main()
{
	int n;
	double num;
	while(scanf("%d",&n)!=EOF)
	{
		priority_queue<double>q;
		while(n--)
		{
			scanf("%lf",&num);
			q.push(num);
		}
		double ans=q.top();//注意n为1的情况 
		while(q.size()>1)
		{
			double a=q.top();
			q.pop();
			double b=q.top();
			q.pop();
			ans=2*sqrt(a*b);
			q.push(ans);
		}
		printf("%.3f\n",ans);
	}
	return 0;
}
  • W-Protecting the Flowers

题解:因为农夫每抱走一头牛,剩下的n-1头牛的问题还是和上面的问题一致。故要想使最终结果最优,所以必须要求当前最优解,所以可以判定是贪心问题。
刚开始,以为先优先d值大的,d值相等时优先t值小的。 WA了,应该优先 t/d 小的。
若先取走a牛,则食花量为 2 t_a d_b ;
若先取走b牛,则食花量为 2 t_b d_a ;
两式分别除以 d_a d_b ;分别为 2 t_a / d_a 2 * t_b / d_b
所以要优先 t/d 值小的。

对于贪心问题n与n-1的策略是相同的,所以由n=2的情况推广到任意n的情况。

注意:O(n^2)算法是会超时的,除去排序情况,其他部分可以优化到O(n)的。

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
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll __int64
using namespace std;
ll sum[100010];
struct node
{
	ll t,d; 
}cow[100010];
 
int cmp(node a,node b)
{
	return (a.t*1.0/a.d)<(b.t*1.0/b.d);
}
 
int main()
{
	int n,i,j;
	ll ans;
	while(scanf("%d",&n)!=EOF)
	{
		for(i=0;i<n;++i)
			scanf("%I64d%I64d",&cow[i].t,&cow[i].d);
		sort(cow,cow+n,cmp);
		sum[n-1]=0;//最后一头牛的消耗为0
		for(i=n-2;i>=0;i--)//其余每头牛的消耗为上一头牛的消耗+本头牛去的时候的消耗
			sum[i]=sum[i+1]+cow[i+1].d;
		ans=0;
		for(i=0;i<n;++i)
			ans+=2*cow[i].t*sum[i]; //遍历一遍得到总的消耗
		printf("%I64d\n",ans);
	}
	return 0;
}
  • X-The Dragon of Loowater
    题意
    有n头龙????和m个骑士,需要让这些骑士杀掉所有的龙,骑士能杀死龙的条件是骑士的身高比龙头的直径要高,每个骑士只能被雇用一次,且雇佣的费用是骑士的身高,求杀死所有龙所需要的最少费用 如果不能杀死所有的龙输出 Loowater is doomed!
    思路
    把龙头的直径和骑士的身高从小到大排序,从第一头龙开始找,然后从所有的骑士里面找能杀死他的,如果找到一个肯定是最小的,然后把他标记上(代表不能再雇佣他了) 如果可以杀死所有的龙????,那么输出答案,否则输出 Loowater is doomed!
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
#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int maxn = 20000+100;
int a[maxn],b[maxn];//数组a代表龙首的个数,b代表骑士身高 
bool bk[maxn];//记录该龙是否被杀死 

int main()
{
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int n,m;//n为龙的个数,m为骑士人数 
    while(cin>>n>>m)
    {
        if(m==0 && n==0)
            break;
        memset(bk,false,sizeof(bk));
        for(int i=0;i<n;i++)
            cin>>a[i];
        for(int i=0;i<m;i++)
            cin>>b[i];
        sort(a,a+n);
        sort(b,b+m);

        int sum=0,cnt=0;
		//sum计数需要的金币数,cnt计数可以被杀死龙的头数 
        for(int i=0;i<m;i++)
        for(int j=0;j<n;j++)
        {
            if(!bk[j] && b[i]>=a[j])
            {
                cnt++;
                sum+=b[i];
                bk[j]=true;
                break;
            }
        }
        if(cnt==n )
            cout<<sum<<"\n";
        else
            cout<<"Loowater is doomed! \n";
    }
}

upload successful
调度问题,直接贪心出完成任务需要的时间最长的那个人排序,就行了。

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
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cmath>
#include<cstring>
#define ll long long
#define pb push_back
#define pm make_pair
#define fi first
#define se second
using namespace std;
const int MAX = 2e5 + 5;
struct Node {
	int a,b;
} node[MAX];
bool cmp(Node a,Node b) {
	return a.b>b.b;  //让执行时间长的排在前面
}
int n;
int main()
{
	int iCase = 0;
	while(~scanf("%d",&n)) {
		if(n == 0) break;
		for(int i = 1; i<=n; i++) scanf("%d%d",&node[i].a,&node[i].b);
		int ans = 0,tmp=0;
		sort(node+1,node+n+1,cmp);
		for(int i = 1; i<=n; i++) {
			tmp += node[i].a;
			ans = max(ans,tmp + node[i].b);
		}
		printf("Case %d: %d\n",++iCase,ans);
	}
 
 
	return 0 ;
}
  • Z - Children’s Game (字典序问题)
    题意
    让你从给定的n个字符串中组成一个字典序最大的字符串
    思路
    如果是9 和 90 两个字符串,如果按照字典序排序的话是909 但是990比它要大,要重载运算符符<,定义a+b > b+a为less真,按字典序从大到小的顺序来排列, 这样排完之后就是字典序最大的字符串了.
    不能挨个位数的比较,要找到好的比较方法。
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
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
using namespace std;
 
string num[55];
 
bool cmp(string a, string b)
{//要转换方法为这样,而不是单纯的比较每位数字的大小(要找到好的排序方法) 
	return a+b > b+a;     //‘+’表示a和b的连接 
}
 
int main()
{
	int n;
	while(scanf("%d", &n), n)
	{
		for(int i=0; i<n; i++)
		{
			cin >> num[i];
		}
		sort(num, num+n, cmp);
		for(int i=0; i<n; i++)
		{
			cout << num[i];
		}
		cout << endl;
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值