hihocoder 编程练习赛75(ABCD都有)

版权声明:转载我的原创博客情注明出处 https://blog.csdn.net/qq_31964727/article/details/82315510

hihocoder 编程练习赛75    

目录

hihocoder 编程练习赛75    

题目1 : 工作城市分配

题意分析:

1.题是什么?

2.思路

ac代码

题目2 : 工作城市分配2

题意分析:

1.题是什么?

2.思路

ac代码

题目3 : 顺子组合

题目分析:

1.题是什么?

2.思路

ac代码

题目4 : 栈的加强版

题意分析:

1.题是什么?

2.思路

ac代码


 

 

题目1 : 工作城市分配

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

H公司在北京和上海两个城市各有一间办公室。该公司最近新招募了2N名员工,小Hi负责把这2N名员工分配到北京和上海各N名。

于是小Hi调查了新员工对于北京和上海的意愿,我们用Bi和Si表示。Bi代表如果分配第i名员工去北京,他的满意指数;Si代表如果分配去上海,他的满意指数。  

小Hi想知道如何分配才能使2N名员工的满意指数之和最高。

输入

第一行包含一个整数N。  

以下2N行每行包含两个整数Bi和Si。  

1 ≤ N ≤ 1000  

0 ≤ Bi, Si ≤ 100000

输出

一个整数代表最高可能的满意指数之和。

样例输入

2  
100 50  
80 80  
50 100  
10 30

样例输出

310

题意分析:

1.题是什么?

    其实就是给你2*n对数字,你要选出其中n对数字取其左数,n对数字取其右数,使得这2*n个数字之和最大化.

2.思路

    略一看有点博弈和背包dp的感觉,因为你选择了这对数的左数就代表你失去了它的右数,怎么去选择才能获取到最大和就是核心问题,而涉及到选择与最优结果自然第一时间该想到dp递推得最优结果.这道题就是dp.

    dp[i][j]表示前面的人分配完之后北京分配i人上海分配j人时可达到的最高满意指数,而递推公式如代码

    (另一个思路:贪心选取,以shanghai[i]-beijing[i]做升序排序,前一半去北京,后一半去上海,这个仅适用与A题)

ac代码

1.dp递推

#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1001;
int beijing[2*maxn],shanghai[2*maxn]; 
int dp[maxn][maxn];//dp[i][j]表示前面的人分配完之后北京分配i人上海分配j人时可达到的最高满意指数

int main(){
	int n;
	cin>>n;
	int ans=0;
	for(int i=1;i<=2*n;i++) cin>>beijing[i]>>shanghai[i]; 
	for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) dp[i][j]=0; 
	for(int i=1;i<=2*n;i++){ //分配第i个人 
		//如果给北京
		for(int j=0;j<=i-1&&j<n;j++) if(i-j-1<=n) dp[j+1][i-j-1]=std::max(dp[j+1][i-j-1],dp[j][i-j-1]+beijing[i]);
		//如果给上海
		for(int j=0;j<=i-1&&j<=n;j++) if(i-1-j+1<=n) dp[j][i-1-j+1]=std::max(dp[j][i-1-j+1],dp[j][i-1-j]+shanghai[i]);
	} 
	cout<<dp[n][n]<<endl; 
	return 0;
}

2.贪心

#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=1001;
typedef pair<int,int> pa;
pa a[2*maxn];//first存的对北京的满意度bi,second存的对上海的满意度si 

bool comp(const pa &a,const pa &b){
	return a.second-a.first<b.second-b.first; //按si-bi升序排序 
}

int main(){
	int n;
	cin>>n;
	for(int i=1;i<=2*n;i++) cin>>a[i].first>>a[i].second; 
	sort(a+1,a+2*n+1,comp);
	int ans=0;
	for(int i=1;i<=n;i++) ans+=a[i].first; //前一半去北京 
	for(int i=n+1;i<=2*n;i++) ans+=a[i].second; //后一半去上海 
	cout<<ans<<endl;
	return 0;
}

题目2 : 工作城市分配2

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

H公司在北京、上海和纽约三个城市各有一间办公室。该公司最近新招募了3N名员工,小Hi负责把这3N名员工分配到北京、上海和纽约各N名。

于是小Hi调查了新员工对于北京、上海和纽约的意愿,我们用Bi、Si和Ni表示。Bi代表如果分配第i名员工去北京,他的满意指数;Si代表如果分配去上海的满意指数;Ni代表如果分配去纽约的满意指数。

小Hi想知道如何分配才能使3N名员工的满意指数之和最高。

输入

第一行包含一个整数N。  

以下3N行每行包含两个整数Bi、Si和Ni。  

1 ≤ N ≤ 100  

0 ≤ Bi, Si, Ni ≤ 100000

输出

一个整数代表最高可能的满意指数之和。

样例输入

2  
100 50 100   
80 80  100  
50 100 100  
10 30 100   
80 40 30  
20 70 50

样例输出

550

 

题意分析:

1.题是什么?

    和A题没什么区别,只是现在是把3*n个人分给3个地方

2.思路

    和A一样,dp

ac代码

#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=101;
int beijing[3*maxn],shanghai[3*maxn],niuyue[3*maxn]; 
int dp[maxn][maxn][maxn];//dp[i][j][k]表示前面的人分配完之后北京分配i人上海分配j人纽约分配k人时可达到的最高满意指数

int main(){
	int n;
	cin>>n;
	for(int i=1;i<=3*n;i++) cin>>beijing[i]>>shanghai[i]>>niuyue[i]; 
	for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) for(int k=0;k<=n;k++) dp[i][j][k]=0; 
	for(int i=1;i<=3*n;i++){ //分配第i个人 
		//如果给北京
		for(int j=0;j<=i-1&&j<n;j++){ //之前给了北京j人 
			for(int k=0;k<=i-1-j&&k<=n;k++){//之前给了上海k人 
				if(i-1-j-k<=n) dp[j+1][k][i-1-j-k]=std::max(dp[j+1][k][i-1-j-k],dp[j][k][i-1-j-k]+beijing[i]); //纽约之前自然是被分配了i-1-j-k人 
			} 
		}
		//如果给上海
		for(int j=0;j<=i-1&&j<=n;j++){ //之前给了北京j人 
			for(int k=0;k<=i-1-j&&k<n;k++){//之前给了上海k人 
				if(i-1-j-k<=n) dp[j][k+1][i-1-j-k]=std::max(dp[j][k+1][i-1-j-k],dp[j][k][i-1-j-k]+shanghai[i]); //纽约之前自然是被分配了i-1-j-k人 
			} 
		}
		//如果给纽约
		for(int j=0;j<=i-1&&j<=n;j++){ //之前给了北京j人 
			for(int k=0;k<=i-1-j&&k<=n;k++){//之前给了上海k人 
				if(i-1-j-k+1<=n) dp[j][k][i-1-j-k+1]=std::max(dp[j][k][i-1-j-k+1],dp[j][k][i-1-j-k]+niuyue[i]); //纽约之前自然是被分配了i-1-j-k人 
			} 
		}
	}
	cout<<dp[n][n][n]<<endl; 
	return 0;
}

题目3 : 顺子组合

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

你有一个包含N个整数的数组:A1, A2, ... AN。我们将3个或3个以上数值连续的整数序列称作顺子,例如[1, 2, 3]、[5, 6, 7, 8]和[10, 11, 12, 13, 14, 15, 16]都是顺子。  

请你判断A数组是否能拆分成若干个顺子的组合。要求每个整数Ai恰好只属于其中一个顺子。

输入

第一行包含一个整数T代表测试数据的组数。  

每组数据第一行包含一个整数N。  

每组数据第二行包含N个整数A1, A2, ... AN。  

1 ≤ T ≤ 10  

1 ≤ N ≤ 10000  

0 ≤ Ai ≤ 100000

输出

对于每组数据输出YES或者NO代表是否能拆分成顺子组合。

样例输入

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

样例输出

YES  
NO

题目分析:

1.题是什么?

   如果是四川人那应该玩过跑得快(也叫蒙鸡),其实题就是给你n个数字,三个或三个以上的相邻数字被认为是连子,如果每个数字都作且仅作为某个连子的一部分,则输出YES,否则NO.

2.思路

    首先发现数字只能在100000以内,故而我选择了使用计数排序那种思想接这n个数字,然后从0到100000挨个判断看是否每个数都是连子的一部分

    length1表示当前位置前方紧接的长度为1的连子数目,length2表示长度为2的连子数目,length3表示长度为3及以上的连子数目

    哪个地方要是有长度为1或2的连子断开了或者说到最后都还有为1或为2的连子存在,自然就NO

ac代码

#include <iostream>
using namespace std;
const int maxa=100001;
int a[maxa];

int main(){
	int t;
	cin>>t;
	while(t--){
		int n,temp;
		cin>>n;
		for(int i=0;i<maxa;i++) a[i]=0;
		for(int i=0;i<n;i++){
			cin>>temp;
			a[temp]++;
		}
		
		bool ans=true;
		int length1=0,length2=0,length3=0;//length1表示当前位置紧接的前方长度为1的连子数目,length2表示长度为2的连子数目,length3表示长度为3及以上的连子数目
		int nu=10;
		for(int i=0;i<maxa;i++){
			if(a[i]>=length1+length2+length3){
				int tlength1=length1,tlength2=length2,tlength3=length3;
				length1=a[i]-(tlength1+tlength2+tlength3);
				length2=tlength1;
				length3=tlength3+tlength2;
			}
			else if(a[i]>=length1+length2){
				length3=a[i]-(length1+length2)+length2;
				length2=length1;
				length1=0;
			}
			else{
				ans=false;
				break;
			}
		}
		if(length1||length2) ans=false;
		if(ans) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
}

题目4 : 栈的加强版

时间限制:10000ms

单点时限:1000ms

内存限制:256MB

描述

请你实现一个加强版的栈,支持以下操作:

push x: 向栈顶加入一个整数x

pop: 从栈顶弹出一个整数,并且输出该整数

inc k x: 将处于栈底的前k个整数加x。

输入

第一行包含一个整数N,代表操作的数量。  

以下N行每行一条操作。  

1 ≤ N ≤ 200000, 0 ≤ x ≤ 100000, 1 ≤ k ≤ 当前栈的大小

输出

对于每一个pop操作,输出弹出的整数数值。

样例输入

6  
push 1  
inc 1 2  
push 2  
inc 2 2  
pop  
pop

样例输出

4  
5

题意分析:

1.题是什么?

    就是要写一个加强的栈,除了原有的push,pop功能之外还要有一个inc功能支持对栈底k个元素全加x

2.思路

    数组模拟栈这是自然的,然后由于操作数最大二十万,对于inc操作不可能真的对栈底部每个数作加x操作,故而我们只用把每次inc操作记录下来,在pop时再加上去,记得还要更新一下被影响到的inc操作.

ac代码

#include <iostream>
using namespace std;
typedef pair<int,int> pa; 
const int maxn=200000;
int a[maxn],top=-1;
int increasing[maxn];


void push(int t){
	a[++top]=t;
}

int pop(){
	if(top>0) increasing[top-1]+=increasing[top];//很重要,对inc的更新
	int ans=a[top]+increasing[top];
	increasing[top]=0; //很重要,对inc的更新
	top--;
	return ans;
}

void inc(int k,int x){
	increasing[k-1]+=x;
}
 
int main(){
	int n;
	cin>>n;
	for(int i=0;i<maxn;i++) increasing[i]=0;
	string order;
	for(int i=0;i<n;i++){
		cin>>order;
		if(order=="push"){
			int t;
			cin>>t;
			push(t);
		}
		else if(order=="pop"){
			cout<<pop()<<endl;
		}
		else if(order=="inc"){
			int t1,t2;
			cin>>t1>>t2;
			inc(t1,t2);
		}
	}
	return 0; 
} 

猜你喜欢

转载自blog.csdn.net/qq_31964727/article/details/82315510