2019.04.20【NOIP提高組】模擬 B 組 觀察題目+堆(?)+最大匹配+貪心、DP

0 壓縮後綴數組

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
據傳是水題
當f[i]=i時,原數組s的i位置一定是偶數,那麼s[i]=a[對應的位置]*2
否則s[i]=s[f[i]]-1

#include <cstdio>

using namespace std;

int n;
int c[20004],a[20004],tot;
int s[20004];

int main(){
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
		scanf("%d",&c[i]);
	for (int i=1;i<=n/2;i++) 
		scanf("%d",&a[i]);
	for (int i=1;i<=n;i++)
	if (c[i]==i) s[i]=a[++tot]*2;
	for (int i=1;i<=n;i++)
	if (c[i]!=i)s[i]=s[c[i]]-1;
	for (int i=1;i<=n;i++)
		printf("%d ",s[i]);
}

1 新年禮物

Windbreaker計劃送一些項鍊給他的朋友們作爲新年禮物。爲了表示誠意,他決定自己製作全部的項鍊。他購買了若干種珍珠,每種珍珠都有特定的顏色。他要製作的項鍊都是M-完美的,也就是每條項鍊都是恰好由M種珍珠組成的。Windbreaker想知道他最多能送出多少條項鍊。給定每種珍珠的數目,你要回答的是Windbreaker最多可以製作多少條M-完美項鍊。

我,應該是水過去的
就每次找出最大的m個數,都減去5(太小超時,太大錯,所以說是水過去的啦),放進堆裏;重複以上步驟知道堆內大於0的不足m個

#include <cstdio> 
#include <queue>
#include <cstring>

using namespace std;

priority_queue<int> q;
int n,m,ans,d;
priority_queue<int> a;

int main(){
	scanf("%d",&n);
	while (n!=0){
		while (!q.empty()) q.pop();
		for (int i=1;i<=n;i++){
			int x;
			scanf("%d",&x);
			q.push(x);
		}
		scanf("%d",&m);
		ans=0;
		while (!a.empty()) a.pop();
		while (q.size()>=m){
			for (int i=1;i<=m;i++){
				a.push(-q.top());
				q.pop();
			}
			if (!q.empty()) d=(-a.top()-q.top()+5); else d=-a.top();
			if (d<0-a.top()) ans+=d; else d=-a.top(),ans+=d;
			for (int i=1;i<=m;i++){
				if (-a.top()-d>0) q.push(-a.top()-d);
				a.pop();
			}
		}
		printf("%d\n",ans);
		scanf("%d",&n);
	}
}

2 聚會

Tzdin想組織一個聖誕晚會。N位女士和M位男士(M>=N)會被邀請參加這個聚會。在聚會的開始,Tzdin會派發一些寫着某位男士信息的卡片給每位女士;每位女士都會收到若干張這種卡片。然後每位女士可以從她收到的卡片裏挑選一位男士作爲她的伴侶。我們可以認爲經過Tzdin的引導,每位女士都一定可以挑選到一位男士作爲他的伴侶,而每位男士最多成爲1位女士的伴侶。Tzdin想知道的是,有哪些男士,無論女士們怎麼選擇,最終都一定會擁有伴侶。

想到是匈牙利算法了呀,方法錯了唄:P
應該先找出最大匹配,然後對於每個女士,讓她不和在最大匹配中的那位男士匹配,如果此時她無法匹配,那麼這個男士滿足一定會有伴侶
畢竟最大匹配是O(n3)O(n^3)

#include <cstdio>
#include <cstring>

using namespace std;

const int N=1001;
int n,m;
int a[1003][1003];
bool b[1003],f[1003];
int s[1003],cover[1003];
int s2[1003];

bool dfs(int w){
	for (int i=1;i<=a[w][0];i++)
	if ((b[a[w][i]])&&(!cover[a[w][i]])){
		int l=s[a[w][i]];
		s[a[w][i]]=w;
		cover[a[w][i]]=1;
		if ((l==0)||(dfs(l))) return 1;
		s[a[w][i]]=l;		
	}
	return 0;
}

bool find(){
	for (int i=1;i<=n;i++){
		memset(cover,0,sizeof cover);
		if (!dfs(i)) return 0; 
	}
	return 1;
}

int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++){
		scanf("%d",&a[i][0]);
		for (int j=1;j<=a[i][0];j++)
			scanf("%d",&a[i][j]);
	}
	memset(b,1,sizeof b);
	memset(f,0,sizeof f);
	find();
	for (int i=1;i<=m;i++){
		b[i]=0;
		memset(cover,0,sizeof cover);
		memcpy(s2,s,sizeof s2);
		if ((s[i]!=0)&&(!dfs(s[i]))) f[i]=1;
		b[i]=1;
		memcpy(s,s2,sizeof s);
	}
	for (int i=1;i<=m;i++)
	if (f[i])
		printf("%d\n",i);
} 

3 遼哥遊戲

張遼是一個長髮飄飄的非常聰明的男孩,人人都稱他爲“遼哥”。遼哥喜歡玩一個有趣的電腦遊戲。這個遊戲開始的時候有n個碉堡,每個碉堡擁有一個防禦值和一個附加值。玩家擁有一個初始的攻擊力。如果玩家破壞了一個碉堡,則他能得到1分。每一次,遼哥會選擇一個碉堡進行攻擊。所有未被破壞的碉堡會聯合起來防禦,因此爲了破壞那個碉堡,遼哥的攻擊力必須大於或者等於所有未被破壞的碉堡的防禦值之和,否則遼哥就會輸掉遊戲。如果遼哥成功破壞了那個碉堡,那麼他的攻擊力會變成那個碉堡的附加值,然後他可以選擇下一個攻擊的目標。

由於遼哥擁有強大的編程能力,他不費吹灰之力就改寫了那個遊戲。在遊戲開始前,他可以用炸彈消滅任意的碉堡,但是他不能通過這種方式來獲得分數。問題來了,在遊戲開始後,遼哥可以得到的最大分數是多少?

據聞是貪心加DP
炸掉碉堡就是不選擇這些碉堡
設f[i]是剩下i個碉堡時所有碉堡最小的防禦值
如果從前往後進行遊戲很麻煩,所以
f[i]=min(f[i],f[i-1]+a[j]) {b[j]>=f[i-1]}
即這時還有i-1個碉堡,要選擇上一個被炸的碉堡;這個被炸的碉堡,需要
防禦值在可選的碉堡中最小
附加值大於已選的所有碉堡

排序就是按照a[i]+b[i]排序

#include <cstdio> 
#include <algorithm>
#include <cstring>

using namespace std;

int n,l,r,ans,s;
struct node{
	int f,g;
}a[1003];
int f[1003];

bool comp(node a,node b){
	return a.f+a.g>b.f+b.g;
}

int main(){
	while (~scanf("%d",&n)){
		memset(a,0,sizeof a);
		for (int i=1;i<=n;i++)
			scanf("%d%d",&a[i].f,&a[i].g);
		scanf("%d",&s);
		sort(a+1,a+1+n,comp);
		memset(f,0x3f,sizeof f);
		f[0]=0;
		for (int i=n;i;i--){
			for (int j=n;j;j--)
			if (a[i].g>f[j-1])
			f[j]=min(f[j],f[j-1]+a[i].f);
		}
		l=0,r=n;
		while (l<=r){
			int mid=(l+r)/2;
			if (f[mid]<=s) ans=mid,l=mid+1;
			          else r=mid-1;
		}
		printf("%d\n",ans);
	}
}

立陽二中、清華醫學系謝俞

在這裏插入圖片描述

“我是謝俞。還有,我不塗黑指甲油”

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