1. 程式人生 > >【xdoj難題集】1039: 飯桌上的遊戲

【xdoj難題集】1039: 飯桌上的遊戲

的連線2014年的壓軸題,又是模擬(話說為什麼最近做了這麼多模擬)。總之又是被無數細節給坑了,不過最後結果不錯,我這個演算法還是挺快的。還是先說說想法,一看到這題的範圍,覺得應該不會超時,比較煩的是標記的這個問題,因為如果每輪都要把標記的人算一次的話怕會超時,不過在看到了飯量最大為5之後我打消了這個顧慮,不過我還是沒有使用常規的方法(導致因為一個細節錯了不少次)。我的想法是因為標記之後死亡的時間是固定的(當然最後發現不盡然),所以只要用一個優先佇列儲存死亡時間和死亡標號即可,因為我的處決機制使得我不拍鞭屍(重複處決),所以即使重複標記也不怕,然後其他的吃飯就都用一個chek函式搞定就行了。具體實現的時候被各種細節問題給坑了1首先構造一組陣列列表,把該存的東西都存了,至於兩種屬性我單開了兩個pair型別的set進行儲存,這樣消除也比較簡單2然後是卡片的問題,這一步出了一個問題,就是我這麼每輪輸入一個的話有可能會因為提前結束而導致輸入的內容不足而影響接下來的結果,所以我修修補補了一下(其實事先用一組陣列儲存更簡單,就是浪費一小點空間)。3接下來是一個重點,我們要根據選擇的卡片進行行動,首先如果要吃飯的就把相應的編號放進chek裡處理即可,如果現在的編號被幹掉了就把編號給前一個,這樣可以保證所有在這個環裡的人都是活著的而且每次向右都是正確的下一個。處理完chek我們處理因為詛咒而需要被處決的人,首先進行迴圈把這些人拉出來一個個幹掉,不過這裡遇到了困擾了我很久的一個問題,就是如果這一步是被標記的就不會有人吃飯,詛咒的也不需要,其實就相當於被續了一秒,不過只要加入一個小機制就可以了,首先我們用一個變數biao記錄標記的次數,這樣每次被標記biao就加一,然後在判斷是否死亡的時候還要加入biao的數量,因為有一些可能是後來加入的所以只要讓死亡時間的部分減去之前(包括自己)標記的數量這樣到時候判斷加上的就是後來標記的數量了。最後貼程式碼
# include <stdio.h>
# include <algorithm>
# include <set>
# include <queue>

using namespace std;

struct man
{
	int ea, y, z;
	int lct, rct;
};

typedef pair<int , int> P;

const int MAX_N = 1005;

bool die[MAX_N];
int T, N, M, now, num;
man stu[MAX_N];
set<P> Y, Z;

void det(int n)
{
	if(die[n])
		return;
	
	num--;
	Y.erase(P(stu[n].y , n));
	Z.erase(P(stu[n].z , n));
	
	stu[stu[n].lct].rct = stu[n].rct;
	stu[stu[n].rct].lct = stu[n].lct;
	
		
	die[n] = true;
	if(n == now)
		now = stu[n].lct; 	
}

inline void chek(int n)
{
	stu[n].ea--;
	
	if(stu[n].ea <= 0)
		det(n);
}

void solve()
{
	fill(die , die + N , 0);
	
	now = 0;
	num = N;
	int b = 0;
	priority_queue<P , vector<P> , greater<P> > que;
	
	int i;
	if(N <= 1)
	{
		for(i = 0 ; i < M ; i++)
			scanf("%d", &now);
		
		printf("%d\n", N);
		return;
	}
	
	
	for(i = 0 ; i < M ; i++)
	{
		int c;
		scanf("%d", &c);

		if(c == 1)
			chek((*Y.begin()).second);
		else if(c == 2)
			chek((*Z.begin()).second);
		else if(c == 3)
		{
			b++;
			que.push(P(i + stu[now].ea - b , now));
		}
		else if(c == 4)
			chek(stu[now].lct);
		else if(c == 5)
			chek(stu[now].rct);
		else 
			chek(now);
			
		while(!que.empty())
		{
			P ty = que.top();
			if(ty.first + b > i)
				break;
				
			que.pop();
			det(ty.second);
		}
		
		int j;
		if(num == 1)
		{
			for(j = i + 1 ; j < M ; j++)
				scanf("%d", &c);
			printf("%d\n", now + 1);
	
			return;
		}
		else if(num == 0)
		{
			for(j = i + 1 ; j < M ; j++)
				scanf("%d", &c);
			puts("0");
			
			return;
		}
		
		now = stu[now].rct;
	}
	
	puts("-1");
}

int main()
{
	scanf("%d", &T);
	
	while(T--)
	{
		Y.clear();
		Z.clear();
		
		scanf("%d %d", &N, &M);
		
		int i, ny, nz;
		for(i = 0 ; i < N ; i++)
			scanf("%d", &stu[i].ea);
			
		for(i = 0 ; i < N ; i++)
			scanf("%d", &stu[i].y);
			
		for(i = 0 ; i < N ; i++)
			scanf("%d", &stu[i].z);
		
		for(i = 0 ; i < N ; i++)
		{
			stu[i].lct = i - 1;
			stu[i].rct = i + 1;
			Y.insert(P(stu[i].y , i));
			Z.insert(P(stu[i].z , i));
		}
		
		stu[0].lct = N - 1;
		stu[N - 1].rct = 0;
		
		solve();
	}
	
	return 0;
}