Problem A. Ascending Rating HDU - 6319(单调队列)

本文介绍了一种使用单调队列求解区间最大值及比较次数的高效算法,通过正向遍历获取最大值,逆向遍历记录比较次数,避免了传统方法的高时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里写图片描述
这里写图片描述

题意:

找到1-n中间每个间隔为m的最大值,和获得这个最大值的比较次数,然后按照题目所给公式将每个区间的结果异或i得到最终结果

分析:

首先观察数据我们知道,一定不能跑二次循环,即每个枚举每个区间,然后在每个区间中再遍历比较最大值并记录次数,这样的复杂度是O(mn)的必然超时,因此我们得想到用O(n)的方法来解决这个问题
那么就是单调队列

我们可以从前往后遍历维护一个单调递减队列,队列中存标号,这样我们就可以得每个区间的最大值
例如3 5 7 9
首先3入队
{3}
然后到5,先将3出队,再将5入队
{5}
然后到7,先将5出队,再将7入队
{7}
最后同理7出队,9入队
{9}
所以最大值是9,即队列的最左端元素是最大的

怎么保证这个最左端元素一定在m的间距范围呢

只需要保证最左端的元素下标,应当大于等于i-m+1,如果小于说明在i区间的左侧,就出队,这样也就是记录了第i个区间的最大值了。

但是我们发现按照这种方式,我们只能得到最大值却不能得到次数

这样因为我们希望较大的值进去后就不在出来了,这样就可以记录下区间内最大值的替换过程
只需要倒着遍历维护单调递减区间即可

还是刚才的例子我们倒着遍历其实是遍历
9 7 5 3
这样9先入队,很明显他是最大的,之后不会破坏单调性,也就不会再出来了
{9}
7入队
{9,7}
5入队
{9,7,5}
3入队
{9,7,5,3}
这样我们相当于一共换了3次,就得到了相应区间的交换次数。

code:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 7e7+10;
typedef long long ll;
int arr[maxn],maxval[maxn],que[maxn],num[maxn];
int n,m,k,p,q,r,mod;
void getMax(int n,int k){
    int head = 0,rear = 0;
    for(int i = 1; i <= n; i++){
        while(rear > head && arr[que[rear-1]] <= arr[i]) rear--;
        que[rear++] = i;
        if(i < k) continue;
        while(que[head] < i - k + 1) head++;
        maxval[i] = arr[que[head]];
    }
}
void getNum(int n,int k){
    int head = 0, rear = 0;
    for(int i = n; i >= 1; i--){//倒着遍历
        while(rear > head && arr[que[rear-1]] <= arr[i]) rear--;
        que[rear++] = i;
        if(i > n - k + 1) continue;
        while(que[head] > i + k - 1) head++;//这里因为是倒着遍历的,所以head++坐标会变小,不断这样下去就可以满足范围了
        num[i] = rear - head;
    }
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d%d%d%d%d%d%d",&n,&m,&k,&p,&q,&r,&mod);
        for(int i = 1; i <= k; i++){
            scanf("%d",&arr[i]);
        }
        for(int i = k + 1; i <= n; i++){
            arr[i] = ((ll)p % mod * arr[i-1] % mod + (ll)q % mod * i % mod + r % mod) % mod;
        }
        getMax(n,m);
        getNum(n,m);
        ll b = 0, a = 0;
        for(int i = 1; i <= n - m + 1; i++){
            b = b + (num[i] ^ i);
            a = a + (maxval[i+m-1] ^ i);
        }
        printf("%lld %lld\n",a,b);
    }
    return 0;
}
根据星历计算卫星位置的方法是比较复杂的,需要用到天文学中的一些计算方法和公式,因此需要一些较为复杂的计算。以下是一个大致的计算流程: 1. 将给定的日期时间转换为儒略日(Julian day)。 2. 根据儒略日计算相应的世纪数。 3. 计算卫星的平近点角(Mean Anomaly)和升交点赤经(Right Ascension of Ascending Node)。 4. 计算卫星的轨道倾角(Inclination)、近地点角距(Argument of Perigee)、半长轴(Semi-Major Axis)等轨道参数。 5. 计算卫星的真近点角(True Anomaly)。 6. 根据卫星的真近点角、轨道参数和世纪数等信息,计算卫星的位置。 下面是一个简单的 C++ 代码示例,可以用来计算给定日期时间的 C01 卫星位置: ```c++ #include <iostream> #include <cmath> using namespace std; const double PI = 3.14159265358979323846; const double GM = 3.986005e14; const double OMEGA_E = 7.2921151467e-5; const double MU_GPS = 3.986005e14; const double C_GPS = 299792458.0; // 计算儒略日 double julian_day(int year, int month, int day, int hour, int minute, int second) { int a = (14 - month) / 12; int y = year + 4800 - a; int m = month + 12 * a - 3; int jdn = day + (153 * m + 2) / 5 + 365 * y + y / 4 - y / 100 + y / 400 - 32045; double jd = jdn + ((double)hour - 12) / 24 + (double)minute / 1440 + (double)second / 86400; return jd; } // 计算卫星位置 void satellite_position(double t, double *pos) { // 从星历中读取轨道参数等信息 double a = 26559700.0; double e = 0.008777161321; double i = 0.9757632172; double O = 0.5405171530; double w = 3.510029399; double M = 0.0; double n = sqrt(MU_GPS / pow(a, 3)); double t0 = 0.0; // 计算平近点角 double E = M + e * sin(M); double E0 = E; while (abs(E - E0) > 1e-12) { E0 = E; E = M + e * sin(E); } double v = 2 * atan(sqrt((1 + e) / (1 - e)) * tan(E / 2)); double r = a * (1 - e * cos(E)); // 计算卫星位置 double x = r * (cos(O) * cos(w + v) - sin(O) * sin(w + v) * cos(i)); double y = r * (sin(O) * cos(w + v) + cos(O) * sin(w + v) * cos(i)); double z = r * sin(w + v) * sin(i); double dt = t - t0; pos[0] = x * cos(OMEGA_E * dt) + y * sin(OMEGA_E * dt); pos[1] = -x * sin(OMEGA_E * dt) + y * cos(OMEGA_E * dt); pos[2] = z; } int main() { int year = 2020; int month = 12; int day = 23; int hour = 23; int minute = 0; int second = 0; double jd = julian_day(year, month, day, hour, minute, second); double t = (jd - 2451545.0) / 36525.0; double pos[3]; satellite_position(t, pos); cout << "C01卫星位置:" << endl; cout << "X = " << pos[0] << " m" << endl; cout << "Y = " << pos[1] << " m" << endl; cout << "Z = " << pos[2] << " m" << endl; return 0; } ``` 注意:由于卫星位置的计算涉及很多天文学中的参数和公式,因此以上代码仅供参考,具体实现需要根据实际情况进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值