長樂爆零之旅 day6 rps
阿新 • • 發佈:2018-12-13
這一題好狗血,用遞推空間炸了,0分,(哭死在廁所 )。
題目:
wzms今年舉辦了一場剪刀石頭布大賽,bleavesbleaves被選為負責人。 比賽共有2^n 個人參加,分為2n輪, 在每輪中,第 1位選手和第 2位選手對戰,勝者作為新的第 1位選手, 第 3位和第 4位對戰,勝者作為新的第 2位選手,以此類推。 調查得知,每個人都有其偏愛決策,每個人在每一次對戰中都會使用他的偏愛決策。 如果一次對戰的雙方的偏愛決策相同,那麼這次對戰就永遠不會結束,所以 不希望這種情況發生。 現在 知道了每個人的偏愛決策,但她不知道如何安排初始的次序,使得上面的情況不會發生,你能幫幫她嗎?
輸入格式:
一行三個整數R,P,SR,P,S ,表示偏愛石頭,布,剪刀的人數分別為R,P,SR,P,S 。
輸出格式:
題解: 這一題還好不會太難,根據題目要求我們求最終的序列,可是我們發現極其不好求,那麼我們換一種思路,我們列舉每種最後勝利者的偏愛(只有三種),根據規則由最後勝利者我們推到參賽者的偏愛,這樣所有的問題就都在字典序上了,我們可以這樣,我們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;
}
明天就要回去了,(不想軍訓 )。