1. 程式人生 > >長樂爆零之旅 day6 rps

長樂爆零之旅 day6 rps

這一題好狗血,用遞推空間炸了,0分,(哭死在廁所 )。 題目: wzms今年舉辦了一場剪刀石頭布大賽,bleavesbleaves被選為負責人。 比賽共有2^n 個人參加,分為2n輪, 在每輪中,第 1位選手和第 2位選手對戰,勝者作為新的第 1位選手, 第 3位和第 4位對戰,勝者作為新的第 2位選手,以此類推。 調查得知,每個人都有其偏愛決策,每個人在每一次對戰中都會使用他的偏愛決策。 如果一次對戰的雙方的偏愛決策相同,那麼這次對戰就永遠不會結束,所以 不希望這種情況發生。 現在 知道了每個人的偏愛決策,但她不知道如何安排初始的次序,使得上面的情況不會發生,你能幫幫她嗎? 輸入格式: 一行三個整數R,P,SR,P,S ,表示偏愛石頭,布,剪刀的人數分別為R,P,SR,P,S 。 輸出格式:

如果無解,輸出 IMPOSSIBLE ; 否則輸出一個長度為R+P+S的字串,第 ii個字元表示初始時第 ii位選手的偏愛決策, 如果有多種方案,輸出字典序最小的。 輸入輸出樣例: 輸入樣例1: 1 1 0 輸出樣例1: PR 輸入樣例2: 2 0 0 輸出樣例2: IMPOSSIBLE 輸入樣例3: 1 1 2 輸出樣例3: PSRS 說明: 樣例解釋1 只有 22個選手,一個偏愛石頭,一個偏愛布,無論次序如何,偏愛布的選手都會勝出。 所以方案可以是 PRPR和 RPRP,其中字典序最小的 。 在這裡插入圖片描述

題解: 這一題還好不會太難,根據題目要求我們求最終的序列,可是我們發現極其不好求,那麼我們換一種思路,我們列舉每種最後勝利者的偏愛(只有三種),根據規則由最後勝利者我們推到參賽者的偏愛,這樣所有的問題就都在字典序上了,我們可以這樣,我們dfs從1,不斷往下dfs每次範圍乘以二(和歸併排序類似,我們不是排序而是分解),然後我們在回溯時左右兩個區間我們可以根據字典序判斷誰在左邊(即前面),這樣我們最後只要找到了就好了,如果沒找到則輸出IMPOSSIBLE 就好了,時間複雜度O(n log n)。 上程式碼:

#include<iostream>
#include<cstdio>
using namespace std;
int r,s,p,ans[1100000],n,R,S,P;//0是布即p,1是石頭即r,2是剪刀即s 
void dfs(int x,int l,int r)//x表示我們的勝利者的偏愛,l和r表示參賽者的範圍,就是總共2^n個人根據排序標號我們現在處理到[l,r]這個範圍的人了 
{
	bool bj=false;//定義標記,在回溯時判斷是否要調換 
	int mid=(l+r)>>1;
	if(l==r)//到了邊界 
	{
		ans[l]=x;
		if(x==
0) P++; if(x==1) R++; if(x==2) S++; return ; } if(x==0)//偏愛是布 { dfs(0,l,mid); dfs(1,mid+1,r); } if(x==1)//偏愛是石頭 { dfs(1,l,mid); dfs(2,mid+1,r); } if(x==2)//偏愛是剪刀 { dfs(0,l,mid); dfs(2,mid+1,r); } for(int i=l;i<=mid;i++)//暴力判斷 { if(ans[i]<ans[mid+i-l+1]) break; if(ans[i]>ans[mid+i-l+1]) { bj=true; break; } } if(bj)//暴力交換 for(int i=l;i<=mid;i++) swap(ans[i],ans[mid+i-l+1]); } int main() { int x; scanf("%d %d %d",&r,&p,&s); x=r+s+p;//計算一下總共x個人 for(int i=0;i<=2;i++)//列舉勝利者的偏愛 { R=0;//清空一下 S=0;//這三個是我們用來統計當前情況下三種偏愛的人的個數 P=0; dfs(i,1,x); if(R==r && S==s && P==p)//如果與題目相符合 { for(int i=1;i<=x;i++)//輸出 { if(ans[i]==0) printf("P"); if(ans[i]==1) printf("R"); if(ans[i]==2) printf("S"); } cout <<endl; return 0;//記得直接return掉,要不然下面的IMPOSSIBLE要用標記 } } printf("IMPOSSIBLE");//沒有輸出的話 return 0; }

明天就要回去了,(不想軍訓 )。