原题 : Problem A. Ascending Rating
题意:
给n个数的数组,求a和b的和
a:每个m长度的子数列的最大值^子数列第一个位置下标
b:每个m长度的子数列的上升数^子数列第一个位置下标
上升数:从第一个开始,遇到大于前一个上升数的所有数(5 2 1 4 6)->(5 6)
解析:
在比赛的时候,我想到了单调栈,但是我是从前往后进栈,这样做的坏处还是很明显的
在删去栈底的较小元素的时候,可能有下面这种情况,5 1 1 1 1 1 6,因为这道题题意的原因,5 6会变成1 1 1 1 1 6,不单单是栈底下扩的问题,对于单调递减的数组n*n的时间我也是…
从后往前维护单调栈,栈底就是最大值,栈size就是上升数
代码:
D read(){ D ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
int arr[10000009];
int q[20000009];int top,bot;
int main(){
int t=read();
while(t--){
int n,len,k,p,qq,r,mo;scanf("%d%d%d%d%d%d%d",&n,&len,&k,&p,&qq,&r,&mo);
for(int i=1;i<=k;i++)scanf("%d",&arr[i]);
for(int i=k+1;i<=n;i++)arr[i]=((D)p*arr[i-1]+(D)qq*i+r)%mo;
D sa=0,sb=0;
top=0;bot=1;
for(int i=n;i>=1;i--){
while(top>=bot&&arr[i]>=arr[q[top]])top--;
q[++top]=i;
int en=i+len-1;
if(i<=n-len+1){
while(q[bot]>en)bot++;sa+=(D)i^arr[q[bot]],sb+=(D)i^(top-bot+1);}
//printf("add %d^%d %d^%d\n",i,arr[q[top]],i,(top-bot+1));
}
printf("%lld %lld\n",sa,sb);
}
}
这题我后来卡了很久,就因为(D)p*arr[i-1]+(D)qq*i+r
,以前我以为一个算式里面有一个long long就不用担心爆int,有一个double就不会爆精度,不过今天我只加了加号前面的部分的强制转换,发现居然WA了…