HDU6319--Ascending Rating(單調隊列複習)

 

忘了單調隊列,順便存下模板

注意算count的是,各自窗口內最大值更新次數(開始讀錯題),而且這裏應該維護反向遞減序列,而正向是不行的比如3  1  2  4,答案應該是2,而維護正向遞增單調隊列會得出3,因爲第一個較大元素可能會丟失。

 

單調隊列核心:無腦入隊,次優值/出窗口範圍出隊,保持單調性。

用到最長上升子序列的O(nlogn)貪心的思想:(之前博客提過,鏈接

對於一個上升子序列,顯然其結尾元素越小,越有利於在後面接其他的元素,也就越可能變得更長

區別在於保持單調方式不同:單調隊列是刪除所有次優值,dp的方法是二分尋找合適位置並替換某個次優值

 

#include<cstdio>
#include<cstring>
#include<queue>
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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章