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);
    }
}

猜你喜欢

转载自blog.csdn.net/sudu6666/article/details/81291509