HDOJ6319
主要看注释(感觉发布格式环境不太顺手)
/*
2018年8月7日15:30:53终于读懂了这段短小精悍的代码,开始反思和复盘,以及思考自己怎么才能写出这么牛逼的代码
2018年8月7日16:06:08去CSDN分享记录一下,万一帮到别人呢
*/
#include<cstdio>
const int N=10000010;
int T,n,m,k,P,Q,R,MOD,i,a[N],q[N],h,t;long long A,B;
int main(){
scanf("%d",&T);
while(T--){
scanf("%d%d%d%d%d%d%d",&n,&m,&k,&P,&Q,&R,&MOD);
for(i=1;i<=k;i++)scanf("%d",&a[i]);
for(i=k+1;i<=n;i++)a[i]=(1LL*P*a[i-1]+1LL*Q*i+R)%MOD;//1ll将int转化为long long
for(h=1,t=A=B=0,i=n;i;i--){//while(n--)的加局部的初始条件的版本
//设计地太精妙,以致我慢慢推他的步骤都有点看不懂,额,我太菜了,去看看百度有没有更详细的解题思路讲解
while(h<=t&&a[q[t]]<=a[i])t--;//这里的while() t--,是确保维护的逆序单调递减队列里面t的值确实等于count改变次数
//有区间控制阀门h<=t
q[++t]=i;//t记录了逆序全过程中所有count+1的次数,而q[t]则正好是当时的位置(这里的代码看了超级久)
if(i+m-1<=n){//从有向左移动了一个区间的时候
while(q[h]>=i+m)h++;//序号过界了,得扯回来(符合一个区间的大小数),所以q[h]是单增序列的最后一个数的下标
//而且这里h和t同级,控制序号数组q[]
A+=i^a[q[h]];//控制的逆序递减序列中,a[q[h]]一定是最大的那个
B+=i^(t-h+1);//从右往左那这里的count一开始是1,和从左往右情况不一定相同,这怎么会对?
//苦恼了半天后面发现题目中没有说小Q教练是严格地安照从左往右数,而是随便找区间
//然后B的求解方程虽然说是安照i=1到n-m+1,但是并没有说count(i)是怎么来的
//上面自己写的一些也是猜的较多,去支持自己的观点,后面自己又读了好多次题目,
//惊呆地发现了我确实又又又读错了,原来是小Q教练在每个区间里面从左往右(每个区间count都是从0开始的!!!)
}
}//在外面找的代码和这个是一样的,还是看这个吧,一个个地慢慢推先
printf("%lld %lld\n",A,B);
}
}