2021算法竞赛入门班第一节课枚举贪心习题

Posted 辉小歌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021算法竞赛入门班第一节课枚举贪心习题相关的知识,希望对你有一定的参考价值。

[USACO 2007 Jan S]保护花朵【经典贪心】


https://ac.nowcoder.com/acm/problem/25043
题解: 很经典的一个贪心问题,你会发现一组牛中相邻的两个牛顺序的改变不会改变其前面的牛的消费,也不会影响后面牛的花费

设A(t1,d1),B(t2,d2)。前面等的总的时间为s
如果先A再B则总的花费为   s*d1+(s+t1*2)*d2
如果先B再A则总的花费为   s*d2+(s+t2*2)*d1

如果A先回去比B先回去更优则:
s*d1+(s+t1*2)*d2<s*d2+(s+t2*2)*d1
s*d1+s*d2+t1*2*d2<s*d2+s*d1+t2*2*d1
最终化简可得:  t1*d2<+t2*d1
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
typedef long long int LL;
typedef pair<int,int> PII;
vector<PII>ve;
int n,a,b;
bool cmp(PII a,PII b) return a.first*b.second<a.second*b.first;
int main(void)

	cin>>n;
	for(int i=0;i<n;i++)
		cin>>a>>b,ve.push_back(a,b);
	sort(ve.begin(),ve.end(),cmp);
	LL s=0,ans=0;
	for(int i=0;i<ve.size();i++)
	
		ans+=s*ve[i].second;
		s+=ve[i].first*2;
	
	cout<<ans;
	return 0;

[NOIP2005]校门外的树【区间合并】


https://ac.nowcoder.com/acm/problem/16649
经典的区间合并,在处理的时候顺便处理计算删除的数量即可。

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
vector<PII>ve;
int n,m,l,r;
int main(void)

	cin>>n>>m;
	while(m--) cin>>l>>r,ve.push_back(l,r);
	sort(ve.begin(),ve.end());
	int l=ve[0].first,r=ve[0].second;
	for(int i=1;i<ve.size();i++)
	
		if(ve[i].first<=r) r=max(r,ve[i].second);
		else
		
			n-=r-l+1;
			l=ve[i].first,r=ve[i].second;
		
	
	n-=r-l+1;
	cout<<n+1<<endl;//+1是因为从0开始
	return 0;

差分做法: 对于删除的区间统一加1,最后统计0的个数即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int s[N],n,m,l,r; 
int main(void)

	cin>>n>>m;
	while(m--)
	
		cin>>l>>r;
		l++,r++;//从将其 [0,n] 变成  [1,n+1]
		s[l]+=1,s[r+1]-=1;
	
	int ans=0;
	for(int i=1;i<=n+1;i++) 
	
		s[i]=s[i]+s[i-1];
		if(!s[i]) ans++;//当前的数为0,说明该树还在
	
	cout<<ans;
	return 0;

[NOIP2006]明明的随机数【签到】


https://ac.nowcoder.com/acm/problem/16669

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],n,x,cnt;
int main(void)

	cin>>n;
	for(int i=0;i<n;i++) 
	
		cin>>x;
		if(!a[x]) cnt++;
		a[x]++;
	
	cout<<cnt<<endl; 
	for(int i=0;i<N;i++) if(a[i]) cout<<i<<" ";
	return 0;

[HNOI2003]激光炸弹【二维前缀和】


https://ac.nowcoder.com/acm/problem/20032

#include<bits/stdc++.h>
using namespace std;
const int N=5010;
int s[N][N],n,m;
int main(void)

	cin>>n>>m; m=min(m,N);
	while(n--)
	
		int x,y,c; cin>>x>>y>>c;
		x++,y++;
		s[x][y]+=c;
	
	for(int i=1;i<N;i++)
		for(int j=1;j<N;j++)
			s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
	int res=0;
	for(int i=1;i<N-m;i++)
		for(int j=1;j<N-m;j++)
		
			int x=i,y=j;
			int xx=i+m-1,yy=j+m-1;
			int temp=s[xx][yy]-s[x-1][yy]-s[xx][y-1]+s[x-1][y-1];
			res=max(res,temp); 
		
	cout<<res<<endl;
	return 0;

铺地毯【枚举】


https://ac.nowcoder.com/acm/problem/16593
题解: 先存一下所有的地毯,然后枚举所有的地毯可不可以覆盖主该点即可。

#include<bits/stdc++.h>
using namespace std;
struct nodeint x,y,g,k;temp;
vector<node>ve;
int n,x,y;
int main(void)

	cin>>n;
	while(n--) 
	
		cin>>temp.x>>temp.y>>temp.g>>temp.k;
		ve.push_back(temp);
	
	cin>>x>>y;
	int ans=-1;
	for(int i=0;i<ve.size();i++)
	
		int l1=ve[i].x,r1=l1+ve[i].g-1;
		int l2=ve[i].y,r2=l2+ve[i].k-1;
		if(x>=l1&&x<=r1&&y>=l2&&y<=r2) ans=i+1;
	
	cout<<ans;

[NOIP2007]纪念品分组【模拟】


https://ac.nowcoder.com/acm/problem/16640
就用双端队列模拟即可,每次取一个最大的和一个最小的看可不可以配对,尽可能多的配对。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int m,n,a[N];
deque<int>q; 
int main(void)

	cin>>m>>n;
	for(int i=0;i<n;i++) cin>>a[i];
	sort(a,a+n);
	for(int i=0;i<n;i++) q.push_back(a[i]);
	int cnt=0;
	while(q.size())
	
		if(q.size()>=2)
		
			auto l=q.front(); q.pop_front();
			auto r=q.back();  q.pop_back();
			if(l+r>m) q.push_front(l);
		else q.pop_back();
		cnt++;
	
	cout<<cnt<<endl;
	return 0;

[NOIP2016]回文日期【日期模拟】


https://ac.nowcoder.com/acm/problem/16438

#include<bits/stdc++.h>
using namespace std;
int month[13]=0,31,28,31,30,31,30,31,31,30,31,30,31;
bool judge(int x)

	if(x%400==0||(x%4==0&&x%100!=0)) return true;
	return false;

bool check(int a,int b,int c)

	string s1=to_string(a);
	while(s1.size()<4) s1="0"+s1;
	string s2=to_string(c);
	while(s2.size()<2) s2="0"+s2;
	s2=to_string(b) +s2;
	while(s2.size()<4) s2="0"+s2;
	string s=s1+s2;
	for(int i=0;i<8/2;i++) if(s[i]!=s[8-1-i]) return false;
	return true;

int main(void)

	int year1,year2,month1,month2,day1,day2;
	string a,b; cin>>a>>b;
	year1=stoi(a.substr(0,4)),month1=stoi(a.substr(4,2)),day1=stoi(a.substr(6,2));
	year2=stoi(b.substr(0,4)),month2=stoi(b.substr(4,2)),day2=stoi(b.substr(6,2));
	int cnt=0;
	if(check(year1,month1,day1)) cnt++;
	while( (year1!=year2) || (month1!=month2) || (day1!=day2) )
	
		day1++;
		if(judge(year1)) month[2]=29;
		if(day1>month[month1]) day1=1,month1++;
		if(month1>12) month1=1,year1++;
		if(check(year1,month1,day1)) cnt++;
		month[2]=28;
	
	cout<<cnt;
	return 0;

以上是关于2021算法竞赛入门班第一节课枚举贪心习题的主要内容,如果未能解决你的问题,请参考以下文章

2021算法竞赛入门班第四节课搜索练习题

2021算法竞赛入门班第七节课图论练习题

2021算法竞赛入门班第九节课线段树练习题

2021算法竞赛入门班第二节课递归分治二分练习题

2021算法竞赛入门班第十节课字符串练习题

2021算法竞赛入门班第三节课堆栈队列并查集等习题