前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >51Nod-1617-奇偶数组

51Nod-1617-奇偶数组

作者头像
f_zyj
发布2018-01-09 11:03:12
5260
发布2018-01-09 11:03:12
举报

ACM模版

描述

描述
描述
描述
描述

题解

这个题的题意有些繁琐,看了好久才看懂。

首先给定一个1~n 序列,要你进行一系列变换,直到没有变化后,然后对该序列进行区间查询。

说起区间查询,很容易想到的就是线段树,可是这个题和线段树有一些差异,因为这个序列变化后是有规律的,划开奇偶看,分别是一个等差数列,所以我们需要处理出来等差数列的第一项就好了。剩下的区间查询就和线段树差不多了,不过不用建树,这倒是一个很有趣的变化。

代码

代码语言:javascript
复制
#include <cstdio>
#include <algorithm>

using namespace std;

long long n, m, mod;
long long l, r, u, v;

long long cal(long long a, long long b, long long c)
{
    a -= b;
    if (a < 0)
    {
        a = -1;
    }
    else
    {
        a = a >> c;
    }

    long long B = b + a * (1ll << c);
    long long s;
    if ((++a) & 1)
    {
        s = (((B + b) >> 1) % mod) * (a % mod);
    }
    else
    {
        s = ((B + b) % mod) * ((a >> 1) % mod);
    }

    return s % mod;
}

long long _cal(long long ll, long long rr, long long c, int d)
{
    if (u > n)
    {
        return 0;
    }

    long long ans = 0;
    if (l > ll || r < rr)
    {
        long long m = (ll + rr) >> 1;
        if (l <= m)
        {
            ans += _cal(ll, m, c, d + 1);
        }
        if (r > m)
        {
            ans += _cal(m + 1, rr, c + (1ll << d), d + 1);
        }
        if (ans >= mod)
        {
            ans -= mod;
        }
    }
    else
    {
        ans = cal(v, c, d) - cal(u - 1, c, d);
        if (ans < 0)
        {
            ans += mod;
        }
    }

    return ans;
}

int main()
{
    scanf("%lld%lld%lld", &n, &m, &mod);

    while (m--)
    {
        scanf("%lld%lld%lld%lld", &l, &r, &u, &v);

        v = min(v, n);
        long long ans = _cal(1, n, 1, 0);

        printf("%lld\n", ans % mod);
    }

    return 0;
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017年09月27日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 描述
  • 题解
  • 代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档