HDU6319--Ascending Rating(单调队列复习)

 

忘了单调队列,顺便存下模板

注意算count的是,各自窗口内最大值更新次数(开始读错题),而且这里应该维护反向递减序列,而正向是不行的比如3  1  2  4,答案应该是2,而维护正向递增单调队列会得出3,因为第一个较大元素可能会丢失。

 

单调队列核心:无脑入队,次优值/出窗口范围出队,保持单调性。

用到最长上升子序列的O(nlogn)贪心的思想:(之前博客提过,链接)

对于一个上升子序列,显然其结尾元素越小,越有利于在后面接其他的元素,也就越可能变得更长

区别在于保持单调方式不同:单调队列是删除所有次优值,dp的方法是二分寻找合适位置并替换某个次优值

 

#include
#include
#include
using namespace std;
typedef long long ll;
const int MAX=1e7+10;
int t,n,m,k;
ll p,q,r,mod;
ll a[MAX];
struct node{
	int id,val;
	node(){}
	node(int a,int b){
		id=a,val=b;
	}
};
node que[MAX];
ll maxrt[MAX],ct[MAX];
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		
		scanf("%d%d%d%lld%lld%lld%lld",&n,&m,&k,&p,&q,&r,&mod);
		for(int i=1;i<=k;i++)
			scanf("%lld",&a[i]);
		for(int i=k+1;i<=n;i++)
			a[i]=(p%mod*a[i-1]%mod + q%mod*i%mod+r%mod)%mod;
			
    //单调队列模板
		int head=1;int tail=0;
		ll ans1=0,ans2=0;
//反向单调递减
		for(int i=n;i>=1;i--)
		{
			while(tail>=head&&que[head].id>=i+m)++head;//移动窗口
			while(tail>=head&&que[tail].val <= a[i])tail--;//次优值出队
			que[++tail]=node(i,a[i]);//新值入队
//end
			if(i+m-1<=n){
                //while(que[head].id>=i+m)++head;//写在这也可
                ans1+=que[head].val^i;
			   ans2+=(tail-head+1)^i;
            }
		}
		
		
		
		printf("%lld %lld\n",ans1,ans2);
	}
	return 0;
}

 

你可能感兴趣的:(—————基础—————,比赛,ACM)