题意:让维护一个栈,每次操作之后询问栈里的最大值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;
}
相关链接: