牛客竞赛 整数序列 线段树+数学

该博客介绍了如何利用线段树和数学技巧解决牛客竞赛中的一道整数序列问题。题目要求对序列进行加法操作和求和sin值的询问,通过sin函数的性质进行优化。需要注意的是,在实现过程中cmath库的sin和cos计算速度可能较慢,可能导致超时。

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

链接:https://ac.nowcoder.com/acm/contest/160/D?&headNav=www
来源:牛客网
 

题目描述

给出一个长度为n的整数序列a1,a2,...,an,进行m次操作,操作分为两类。
操作1:给出l,r,v,将al,al+1,...,ar分别加上v;
操作2:给出l,r,询问∑i=lrsin(ai)\sum\limits_{i=l}^{r}sin(a_i)i=l∑r​sin(ai​)

输入描述:

第一行一个整数n
接下来一行n个整数表示a1,a2,...,an
接下来一行一个整数m
接下来m行,每行表示一个操作,操作1表示为1 l r v,操作2表示为2 l r
保证1≤n,m,ai,v≤200000;1≤l≤r≤n,v是整数

输出描述:

对每个操作2,输出一行,表示答案,四舍五入保留一位小数
保证答案的绝对值大于0.1,且答案的准确值的小数点后第二位不是4或5
数据随机生成(n,m人工指定,其余整数在数据范围内均匀选取),并去除不满足条件的操作2

示例1

输入

4
1 2 3 4
5
2 2 4
1 1 3 1
2 2 4
1 2 4 2
2 1 3

输出

0.3
-1.4
-0.3

思路:根据sin(a+v)=sin(a)cos(v)+cos(a)sin(v),cos(a+v)=cos(a)cos(v)-sin(a)sin(v)维护即可。注意一点,cmath中求sin,cos还是挺慢的,写法有问题会T。。。

#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn=2e5+10;
const double eps=1e-8;
double a[maxn];
struct node{
    int l;
    int r;
    double laz;
    double sumcos;
    double sumsin;
}tree[maxn<<2];
int n,m;
void pushup(int cur)
{
    tree[cur].sumsin=tree[cur<<1].sumsin+tree[cur<<1|1].sumsin;
    tree[cur].sumcos=tree[cur<<1].sumcos+tree[cur<<1|1].sumcos;
}
void pushdown(int cur)
{
    double sinval,cosval,tsin,tcos;
    if(fabs(tree[cur].laz)>eps)
    {
        sinval=sin(tree[cur].laz),cosval=cos(tree[cur].laz);
        tsin=tree[cur<<1].sumsin,tcos=tree[cur<<1].sumcos;
        tree[cur<<1].sumsin=tsin*cosval+tcos*sinval;
        tree[cur<<1].sumcos=tcos*cosval-tsin*sinval;
        tree[cur<<1].laz+=tree[cur].laz;
        tsin=tree[cur<<1|1].sumsin,tcos=tree[cur<<1|1].sumcos;
        tree[cur<<1|1].sumsin=tsin*cosval+tcos*sinval;
        tree[cur<<1|1].sumcos=tcos*cosval-tsin*sinval;
        tree[cur<<1|1].laz+=tree[cur].laz;
        tree[cur].laz=0.0;
    }
}
void build(int l,int r,int cur)
{
    tree[cur].l=l;
    tree[cur].r=r;
    tree[cur].laz=0.0;
    if(l==r)
    {
        tree[cur].sumsin=sin(a[l]);
        tree[cur].sumcos=cos(a[l]);
        return ;
    }
    int m=(l+r)>>1;
    build(l,m,cur<<1);
    build(m+1,r,cur<<1|1);
    pushup(cur);
}
void update(int L,int R,double val,int cur)
{
    double sinval,cosval,tsin,tcos;
    if(L<=tree[cur].l&&tree[cur].r<=R)
    {
        sinval=sin(val),cosval=cos(val),tsin=tree[cur].sumsin,tcos=tree[cur].sumcos;
        tree[cur].sumsin=tsin*cosval+tcos*sinval;
        tree[cur].sumcos=tcos*cosval-tsin*sinval;
        tree[cur].laz+=val;
        return ;
    }
    pushdown(cur);
    if(L<=tree[cur<<1].r) update(L,R,val,cur<<1);
    if(R>tree[cur<<1].r) update(L,R,val,cur<<1|1);
    pushup(cur);
}
double query(int L,int R,int cur)
{
    if(L<=tree[cur].l&&tree[cur].r<=R) return tree[cur].sumsin;
    double res=0.0;
    pushdown(cur);
    if(L<=tree[cur<<1].r) res+=query(L,R,cur<<1);
    if(R>tree[cur<<1].r) res+=query(L,R,cur<<1|1);
    return res;
}
int main()
{
    int n,op,x,y;
    double z;
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lf",&a[i]);
    build(1,n,1);
    scanf("%d",&m);
    while(m--)
    {
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d%lf",&x,&y,&z);
            update(x,y,z,1);
        }
        if(op==2)
        {
            scanf("%d%d",&x,&y);
            double ans=query(x,y,1);
            printf("%.1lf\n",ans);
        }
    }
    return 0;
}

 

### 牛客竞赛算法资料与题解汇总 牛客竞赛作为国内知名的在线编程竞赛平台,提供了丰富的算法题目和学习资源。以下是关于牛客竞赛算法相关的资料、教程以及题解的整理: #### 1. **牛客竞赛基础入门** 牛客竞赛提供了一系列的基础训练营,帮助初学者逐步掌握算法知识。例如,2024牛客寒假算法基础集训营1[^2],涵盖了从简单到复杂的算法问题,适合新手进行系统性学习。 ```python # 示例代码:快速幂实现 def ksm(a, k, mod): res = 1 while k: if k & 1: res = (res * a) % mod k >>= 1 a = (a * a) % mod return res ``` #### 2. **牛客多校赛题解** 牛客多校赛是每年的重要赛事之一,吸引了大量高水平选手参与。以2023年第八场牛客多校赛为例[^3],其题解中详细分析了如何通过维护右端点来寻找合法左端点的问题。这种方法结合了贪心和前缀和的思想,具有很强的实用性。 #### 3. **图论相关问题** 图论是算法竞赛中的重要分支,许多选手在图论题目上感到困难。例如,在一场竞赛中提到:“自己的图论知识还是很菜,写不了码量很大的题目”[^1]。这表明加强图论的学习尤为重要。推荐参考《牛客算法竞赛入门笔记》[^4],其中包含了对图论问题的深入讲解。 #### 4. **贪心算法与前缀和** 贪心算法在竞赛中非常常见,尤其是在处理区间问题时。例如,在解决“why买外卖”问题时,采用了贪心加前缀和的方法[^2]。这种思路可以有效减少时间复杂度,提高程序效率。 #### 5. **二分查找与数值优化** 在某些数值优化问题中,二分查找是一种高效的方法。例如,以下代码展示了如何通过二分查找找到满足条件的最大值或最小值[^4]: ```cpp double l = 0, r = 1e11 + 1; while (r - l > 1e-6) { // 控制精度 double mid = (l + r) / 2; if (fun(mid)) { l = mid; } else { r = mid; } } printf("%.6lf\n", l); ``` #### 6. **其他学习资源** - **牛客博客**:牛客平台上有很多优秀的博主分享他们的竞赛经验和技术文章。 - **官方题解**:每场比赛结束后,牛客都会发布官方题解,详细解析每道题目的解法。 - **讨论区**:牛客竞赛的讨论区是一个很好的交流平台,可以向其他选手请教问题。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值