2018 ACM-ICPC 寧夏邀請賽 A. Maximum Element In A Stack(思路題)
阿新 • • 發佈:2019-02-20
題意:讓維護一個棧,每次操作之後詢問棧裡的最大值xi,求(1*x1)^(2*x2)^……^(n*xn)的結果。
思路分析:首先暴力每次入棧找最大值肯定T,現場賽時我們隊想到的思路是維護一個stack和一個multiset(或者map),每次push最大值是m.end()-1對應的值,pop的話,在stack裡找到top,然後在multiset裡find值對應的迭代器erase。抱著僥倖態度WA了10多發,卡了我們一個半小時,這個全場題導致最後我們與銀牌無緣。後來反思,這是一道思路題,正確的做法是每次push時將將入棧元素與棧頂元素cmp一下,push大的值,而pop的時候直接pop棧頂元素,由於堆疊先入後出的特性,較小元素在較大元素之後加入stack不會影響每次操作後所求的最大值,最大值永遠不可能是後加入的較小元素,所以它具體是多少就變得無關緊要了,那麼就可以把它改成最大值,這樣的話無論怎樣操作,總能保證棧頂元素 = 棧內最大值。即使清楚了思路,今天網路賽仍然WA了三次,這個題爆int,原因是i與xi相乘時可能超出int範圍。
AC程式碼:
#include <bits/stdc++.h> using namespace std; int n,p,q,m; unsigned int SA,SB,SC; stack<long long>s; void PUSH(long long x){ if(s.empty())s.push(x); else s.push(max(x,s.top())); } void POP(){ if(!s.empty()) s.pop(); } unsigned int rng61(){ SA ^= SA << 16; SA ^= SA >> 5; SA ^= SA << 1; unsigned int t = SA; SA = SB; SB = SC; SC ^= t ^ SA; return SC; } int main(){ int T; scanf("%d",&T); for(int t = 1;t <= T;t++){ while(!s.empty())s.pop(); long long ans = 0; scanf("%d%d%d%d%u%u%u",&n,&p,&q,&m,&SA,&SB,&SC); for(int i = 1;i <= n;i++){ if(rng61() % (p + q) < p)PUSH(rng61() % m + 1); else POP(); if(!s.empty())ans ^= (i*s.top()); } printf("Case #%d: %lld\n",t,ans); } return 0; }
標程:
#include<bits/stdc++.h> using namespace std; const int MAXN=5000005; int stk[MAXN],top,res[MAXN]; int n, p, q, m; unsigned int SA,SB,SC; unsigned int rng61() { SA ^= SA << 16; SA ^= SA >> 5; SA ^= SA << 1; unsigned int t = SA; SA = SB; SB = SC; SC ^= t ^ SA; return SC; } long long solve() { scanf("%d%d%d%d%u%u%u",&n,&p,&q,&m,&SA,&SB,&SC); long long res=(top=0); for(int i=1;i<=n;i++) { if(rng61()%(p+q)<p) { ++top; stk[top]=rng61()%m+1; stk[top]=max(stk[top],stk[top-1]); } else top=max(top-1,0); res^=1LL*i*stk[top]; } return res; } int main() { int T; scanf("%d",&T); for(int ca=1; ca<=T; ca++) printf("Case #%d: %lld\n",ca,solve()); return 0; }
相關連結: