HOJ多校联合练习 A. Ascending Rating

 

问题 A: Problem A. Ascending Rating

时间限制: 5 Sec  内存限制: 512 MB
提交: 18  解决: 6
[提交] [状态] [讨论版] [命题人:admin]

题目描述

Before the start of contest, there are n ICPC contestants waiting in a long queue. They are labeled
by 1 to n from left to right. It can be easily found that the i-th contestant’s QodeForces rating is ai.
Little Q, the coach of Quailty Normal University, is bored to just watch them waiting in the queue.
He starts to compare the rating of the contestants. He will pick a continous interval with length m,
say [l, l + m − 1], and then inspect each contestant from left to right. Initially, he will write down two
numbers maxrating = 0 and count = 0. Everytime he meets a contestant k with strictly higher rating
than maxrating, he will change maxrating to ak and count to count + 1.
Little T is also a coach waiting for the contest. He knows Little Q is not good at counting, so he
is wondering what are the correct final value of maxrating and count. Please write a program to figure
out the answer. 
 
Note that “⊕” denotes binary XOR operation. 
/upload/file/20180730/20180730153658_79891.pdf
 

 

样例输入

1
10 6 10 5 5 5 5
3 2 2 1 5 7 6 8 2 9

样例输出

46 11

[提交][状态]

题意:给定一个序列a[1..n],对于每个长度为m 的连续子区间,求出区间a 的最大值以及从左往右扫描该区间时a 的最大值的
变化次数。

题解:又借着这道题复习了一遍单调队列和单调栈,这两个数据结构是真......的好玩....,这也算是这次最大的收获了,正解的单调队列,对于这个区间如果按照l从小到大枚举是不好处理的,可以将l从大到小去枚举,这样用滑动窗口的单调队列,对于一个元素,若队列为空,则直接入队,若大于队列尾元素,则将队尾出队列直到小于队尾或者队列空,然后入队,若当前元素小于队列尾,则直接入队,同时若对头元素超出窗口的范围,则将队头元素++,如此队头元素便是这个滑动区间的最大值

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e7+1005;
typedef long long ll;

int a[maxn],q[maxn];
ll A,B;

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,m,k,p,Q,r,mod;
        scanf("%d %d %d %d %d %d %d",&n,&m,&k,&p,&Q,&r,&mod);

        for(int i=1;i<=k;i++) scanf("%d",&a[i]);
        for(int i=k+1;i<=n;i++) a[i]=(1LL*a[i-1]*p+1LL*Q*i+r)%mod;

        int top,i,h;
        for(i=n,h=1,A=B=top=0;i;i--)
        {
            while(h<=top && a[q[top]]<=a[i] ) top--;
            q[++top]=i;
            if(i+m-1<=n)
            {
                while(q[h]>=i+m) h++;
                A+=i^a[q[h]];
                B+=i^(top-h+1);
            }
        }

        printf("%lld %lld\n",A,B);
    }
    return 0;
}

同时在次附上学长的单调栈的代码~~~~

/****
***author winter2121
***
****/
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int MAX=1e7+5;
const int INF=0x3f3f3f3f;

//int read(){int x;scanf("%d",&x);return x;}
int read()
{
    int x=0,sig=1;
    char c;
    for (c=getchar();c<'0' || c>'9';c=getchar()) if (c=='-') sig=-1;
    for (;c>='0' && c<='9';c=getchar()) x=x*10+c-48;
    return x*sig;
}

int n,m,k,p,q,r,MOD,T;
int a[MAX];
int st[MAX]; //栈
int fir[MAX]; //i右边第一个大于a[i]的位置
int dp[MAX]; //以i起始的最长上坡
int main()
{
    T=read();
    while(T--)
    {
        n=read(); m=read(); k=read(); p=read(); q=read(); r=read(); MOD=read();
        for(int i=1;i<=k;i++)scanf("%d",&a[i]);
        for(int i=k+1;i<=n;i++)a[i]=(1ll*p*a[i-1]+1ll*q*i+r)%MOD;
        int top=0;
        for(int i=1;i<=n;i++)
        {
            while(top&&a[ st[top] ]<a[i])
                fir[ st[top--] ]=i;
            st[++top]=i;
        }
       
        for(int i=n;i>=1;i--)dp[i]=dp[fir[i]]+1;
       
        top=0;
        unsigned long long ans1=0,ans2=0;
        for(int i=1,j=1;i<=n-m+1;i++)
        {
            while(top&&st[top]<i)top--;
            if(top==0)j=i; //若空,则从新开始
            while(j<=i+m-1)
            {
                if(a[j]>a[ st[top] ])st[++top]=j;
                j++;
            }
            int t=st[top];
            int Count=dp[i]-dp[t]+1;
            int maxrating=a[t];
            ans1+=maxrating^i;
            ans2+=Count^i;
        }
        printf("%llu %llu\n",ans1,ans2);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值