【紀中2020.3.11日】模擬賽題解

目錄:

T1:水果盛宴
T2:憤怒的奶牛2
T3:採訪
T4:房間開燈

這次竟然又變成4道題了,而且大部分都是USACO題。

正題:

T1:水果盛宴

題目描述

貝茜又再一次地闖入了 Farmer John 的房子!她在廚房發現了一堆檸檬和一堆橘子(每堆都有無限多個),並且,她希望儘可能地多喫。
貝茜的有一個飽腹值上限 T(1<=T<=5,000,000)。喫一個橘子會增加她 A 點飽腹值,喫一個檸檬會增加她 B 點飽腹值(1<=A,B<=T),如果她願意,貝茜可以最多喝一次水,這會立即使她的飽腹值變成一半,請你幫助貝茜求出她可以獲得的最大飽腹值。

輸入

一行三個整數 T,A 和 B

輸出

一行一個整數,表示貝茜可獲得的最大飽腹值

樣例輸入

8 5 6

樣例輸出

8

分析:

這道題做法有很多種,可以用遞歸來解決。
具體一點就是從0開始去遞歸它出現的所有情況,在裏面找一個最大值,注意越界和重複情況。O(N),跑得挺快。

CODE:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
bool f[5000001];  //判斷重複用f數組標記
int t,a,b,ans;
void digui(int dep,int rp){   //遞歸函數
	if(f[dep]||dep>t) return;  //越界及重複
	if(dep>ans) ans=dep;  //最大值
	f[dep]=1;  //標記
	digui(dep+a,rp);
	digui(dep+b,rp);  //三種條件
	if(rp==0) digui(dep/2,1);  
}
int main(){
	freopen("fruit.in","r",stdin);
	freopen("fruit.out","w",stdout);
	cin>>t>>a>>b;
	digui(0,0);  //從0開始遞歸
	cout<<ans;
	return 0;
}

T2:憤怒的奶牛2

題目描述

貝茜這頭奶牛設計了她所認爲的下一個熱門視頻遊戲—“憤怒的奶牛”。她認爲這是她完全原創的:玩家將一個彈弓射到一個一維的場景中,該場景由位於數字線上各個點的一組乾草包組成。每隻奶牛都有足夠的力量引爆其落地地點附近的乾草包,我們的目的是使用一系列奶牛引爆所有的乾草包。
有N捆乾草包位於這一行的不同整數位置x1,x2,…,xN,如果一頭奶牛以能量R着陸在了數軸上的任意一個位置x,那麼會引起半徑爲R(R-x…R+x)的爆炸,並摧毀範圍內的所有乾草包。
一共有K頭奶牛允許被用來作爲炮彈,每頭奶牛的能量R都相同。請幫忙決定這個最小的能量,使得用這K頭奶牛可以摧毀所有的乾草包。

輸入

第一行包含兩個整數N,K(1<=N<=50,000,1<=K<=10)
接下來N行,每行包含一個整數xi,表示每捆乾草包的位置(0<=xi<=1,000,000,000)

輸出

一行一個整數,表示最少所需要的每頭奶牛的能量值R

樣例輸入

7 2
20
25
18
8
10
3
1

樣例輸出

5

分析:

這道題是二分答案
先手打個快排,然後就二分
二分過程就是我們二分它的答案R每次判斷取mid時候是否炸掉所有的,可以就向前,不然向後

CODE:

#include<cmath>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long LL;
int a[50001];
int l,r,i,j,k,n,m,mid;
void fff(int l,int r){  //手打快排
	int i,j,mid;
	if(l>=r) return;
	i=l;j=r;
	mid=a[(l+r)/2];
	do{
		while(a[i]<mid) i++;
		while(a[j]>mid) j--;
		if(i<=j){
			a[0]=a[i];a[i]=a[j];a[j]=a[0];
			i++;j--;
		}
	}while(i<=j);
	if(l<j) fff(l,j);if(i<r) fff(i,r);
}
int main(){
	freopen("angry.in","r",stdin);
	freopen("angry.out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m;
	for(i=1;i<=n;i++)
	cin>>a[i];
	fff(1,n);
	l=0;r=(a[n]-a[1]+1)/m+1;  //取r初始位置
	while(l+1<r){
	 //開始二分
		j=1;
		mid=(l+r)/2;
		k=0;
		for(i=1;i<n;i++)
		{
			k=k+(a[i+1]-a[i]);
			if(k>2*mid){
			//炸掉的乾草堆個數
				j++;k=0;
			}
		}
		if(j<=m) r=mid;  //判斷是否能全部炸
		else l=mid;
	}
	cout<<r;
return 0;
}

T3:採訪

題目描述

你是一名記者,現在要求你去採訪n 個國家的領導人。採訪每一個國家的領導人需要消耗你的時間爲t[i],但你可以收穫價值爲v[i]的信息,然後就能寫成報道……
然而尷尬的是,有一些國家之間的關係屬於敵對關係,因此如果一個國家的領導人知道你採訪了他的敵對國家領導人,那麼他就會拒絕你的採訪。總之,你採訪的國家中,任意選出一對國家都不能構成敵對關係,你才能夠完成你的採訪,否則某些部分就要落空。
你的Boss他給了你一個時間限制T,如果你在時間限制內沒有完成採訪任務,你就會被炒魷魚。當然,他希望你在時間限制T 內完成的採訪累計起來的價值總和最大。

輸入

第一行有三個數,第一個數爲時間限制T,第二個數爲國家數量n,第三個數爲國家之間的敵對組數m。
接下來n 行,每行兩個數,第一個數爲t[i],第二個數爲v[i]。
接下來m 行,每行有m[i]+1 個數,首先輸入m[i],表示這一組中一共有多少國家是敵對關係,之後輸入m[i]個數,表示這m[i]個國家兩兩之間爲敵對關係(一組敵對關係的國家中,每兩個國家都構成敵對關係,比如這一組是1,3,4,那麼1 和3,1 和4,3 和4 都構成敵對關係),若m[i] = 1,那麼這個國家與其他國家都不構成敵對關係。

輸出

一個整數,表示最大價值V。

樣例輸入

10 5 2
5 10
7 9
6 3
1 13
8 1
3 1 3 4
2 2 5

樣例輸出

22

分析:

樣例就知道是dp。
dalao講的還是個分組揹包
設f[i,j]表示前i個關係圈花費時間爲j能獲得的最大價值總和是多少。 f[i,j]=max{f[i-1,j-t[i,k]]+v[i,k]}
i枚舉關係圈 j枚舉時間 k枚舉i關係圈的某個領導人
四重for不會超時

CODE:

#include<iostream>
#include<cstdio>
using namespace std;
int m,n,k,x,y;
int t[1010],v[1010];
int f[11][5001];
int a[100][100];
int main(){
	freopen("interview.in","r",stdin);
	freopen("interview.out","w",stdout);
	cin>>n>>k>>m;
	for(int i=1;i<=k;i++){
		cin>>t[i]>>v[i];
	}
	for(int i=1;i<=m;i++){
		cin>>a[i][0];
		for(int j=1;j<=a[i][0];j++)
		cin>>a[i][j];
	}
	for(int i=1;i<=m;i++){  //枚舉關係圈
		for(int j=0;j<=n;j++)f[i][j]=f[i-1][j];  //枚舉時間
		for(int k=1;k<=a[i][0];k++){  //枚舉領導人
			for(int j=n;j>=t[a[i][k]];j--)
			f[i][j]=max(f[i][j],f[i-1][j-t[a[i][k]]]+v[a[i][k]]);  //最大值總和
		}
	}
	cout<<f[m][n];
	return 0;
}

T4:房間開燈

題目描述

Farmer John 最近正在修建一個巨大的包含 N×N 個房間的牲口棚,這些房間從(1,1)標號到(N,N)。由於某些原因而害怕黑暗,貝茜這頭奶牛想要儘可能地開更多房間的燈。貝茜從房間(1,1)出發,這個房間是唯一一個一開始就亮着的房間。在一些房間中,她會找到一些電燈開關,這些開關她可以用來切換其他房間的燈的狀態。比如,在(1,1)這個房間中可能存在一個電燈開關來控制(1,2)房間中的電燈。貝茜只能進電燈開着的房間,並且貝茜只能從房間(x,y)走到四個方向的房間(x-1,y),(x+1,y),(x,y-1)和(x,y+1)(如果在邊界的話,那可能會更少)。請幫忙統計貝茜最多可以照亮多少房間。

輸入

第一行兩個整數 N,M(2<=N<=100,1<=M<=20,000)
下面 M 行,每行用四個整數 x,y,a,b 來表示房間(x,y)存在着可以控制房間(a,b)的燈的開關。一個房間可能有多個開關,一個房間的燈的開關可能存在於多個房間中。

輸出

一行一個整數,表示貝茜最多可以照亮的房間數

樣例輸入

3 6
1 1 1 2
2 1 2 2
1 1 1 3
2 3 3 1
1 3 1 2
1 3 2 1

樣例輸出

5

分析:

這道題原來是個bfs?我笑了。
鄰接表記錄一個點與它連接的開關,用ans記錄當前有多少個亮燈。每加入一個點,就枚舉與它連接的開關,看是否能到達一個亮燈的地方。

CODE:

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,next[20001],sx[20001],sy[20001],ex[20001],ey[20001];
int head[101][101],a[101][101],f[101][101];
int b[100100][3],ans;
int dx[4]={0,1,0,-1};  //導航
int dy[4]={1,0,-1,0};
void bfs(){
	b[1][1]=1;b[1][2]=1;
	a[1][1]=1;
	f[1][1]=1;
	ans++;
	int hd=0,tail=1;
	while(hd<tail){  //廣搜
		hd++;
		int x1=head[b[hd][1]][b[hd][2]];
		while(x1!=0){
			if(a[ex[x1]][ey[x1]]==0) ans++;  //亮燈
			a[ex[x1]][ey[x1]]=1;  //連接
			x1=next[x1];
		}
		for(int i=1;i<=hd;i++){  //繼續枚舉能否到達亮燈
			for(int j=0;j<4;j++){
				int xx=b[i][1]+dx[j];
				int yy=b[i][2]+dy[j];
				if(a[xx][yy]==1&&f[xx][yy]!=1){
					tail++;
					b[tail][1]=xx;
					b[tail][2]=yy;
					f[xx][yy]=1;
				}
			}
		}
	}
}
int main(){
	freopen("light.in","r",stdin);
	freopen("light.out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>sx[i]>>sy[i]>>ex[i]>>ey[i];
		next[i]=head[sx[i]][sy[i]];
		head[sx[i]][sy[i]]=i;
	}
	bfs();
	cout<<ans;
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章