题解 P5278 【算术天才⑨与等差数列】

题目链接

这题并不用维护什么\(20\)次方和鸭,双模数\(hash\)怼过去,莫名其妙跑的贼快

Solution 算术天才⑨与等差数列

题目大意:给定一个长度为\(n\)的数列,每次询问\([l,r]\)可否重排成一个公差为\(k\)的等差数列,强制在线

分析:

前置芝士:P3792 由乃与大母神原型和偶像崇拜虽然不用做这题也行

如果你做过上面一题,大概就会对用类似于\(hash\)的思想来解决数列重排问题有一定的了解,这题我们用类似的思路,维护区间平方和:

首先,我们设这个等差数列的首项为\(x\),项数为\(n\),公差为\(k\),那么:

\[hash = \sum_{i = 0}^{n - 1}{(x + ik) ^ 2}\]

平方差公式打开括号:

\[hash = \sum_{i = 0}^{n - 1}{(x ^ 2 + 2xik + i^2k^2)}\]

\[= nx^2 + 2xk\sum_{i = 0}^{n - 1}{i} + k^2\sum_{i = 0}^{n - 1}{i^2}\]

然后:

\[\sum_{i = 0}^{n - 1}i = \frac{(0 + n - 1)\times n}{2} = \frac{n(n-1)}{2}\]

\[\sum_{i = 0}^{n - 1}i^2 = \frac{(n - 1)\times n \times[2(n - 1) + 1]}{6} = \frac{n(n-1)(2n-1)}{6}\]

\[\therefore hash = nx^2 + xkn(n-1) + \frac{k ^ 2n(n-1)(2n-1)}{6}\]

然后我们来选择模数:您可以尝试选择某八位质数,感受东方神秘力量

\(10^9 + 7\)和\(10^9 + 9\)是一对孪生素数,就选择它们了,因为涉及到除法,所以在取模意义下我们只能乘它们的逆元

\[6^{-1} \equiv 166666668(mod\;10^9+7)\]

\[6^{-1} \equiv 833333341(mod\;10^9+9)\]

然后线段树维护一下区间\(min\)即可求出首项,上代码:

注意:代码中运用了C++新特性,请使用C++17编译

#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 100,mod1 = 1e9 + 7,mod2 = 1e9 + 9,INF = 0x7fffffff;
template <typename T>
inline T min(const T &a,const T &b){return a < b ? a : b;}
int val[maxn];
inline int read(){
    int x = 0;char c = getchar();
    while(c < '0' || c > '9')c = getchar();
    while(c >= '0' && c <= '9')x = x * 10 + c - '0',c = getchar();
    return x;
}
namespace ST{
    struct Node{
        int l,r,val1,val2,valm;
    }tree[maxn << 2];
    #define lson (root << 1)
    #define rson (root << 1 | 1)
    #define mid ((tree[root].l + tree[root].r) >> 1)
    inline void maintain(int root){
        tree[root].valm = min(tree[lson].valm,tree[rson].valm);
        tree[root].val1 = (tree[lson].val1 + tree[rson].val1) % mod1;
        tree[root].val2 = (tree[lson].val2 + tree[rson].val2) % mod2;
    }
    void build(int a,int b,int root = 1){
        tree[root].l = a;
        tree[root].r = b;
        if(a == b){
            tree[root].valm = val[a];
            tree[root].val1 = (ll(val[a]) * val[a]) % mod1;
            tree[root].val2 = (ll(val[a]) * val[a]) % mod2;
            return;
        }
        build(a,mid,lson);
        build(mid + 1,b,rson);
        maintain(root);
    }
    int query_min(int a,int b,int root = 1){
        if(a <= tree[root].l && b >= tree[root].r)return tree[root].valm;
        int ret = 0x7fffffff;
        if(a <= mid)ret = min(ret,query_min(a,b,lson));
        if(b >= mid + 1)ret = min(ret,query_min(a,b,rson));
        return ret;
    }
    int query_val1(int a,int b,int root = 1){
        if(a <= tree[root].l && b >= tree[root].r)return tree[root].val1;
        int ret = 0;
        if(a <= mid)ret += query_val1(a,b,lson),ret %= mod1;
        if(b >= mid + 1)ret += query_val1(a,b,rson),ret %= mod1;
        return ret;
    }
    int query_val2(int a,int b,int root = 1){
        if(a <= tree[root].l && b >= tree[root].r)return tree[root].val2;
        int ret = 0;
        if(a <= mid)ret += query_val2(a,b,lson),ret %= mod2;
        if(b >= mid + 1)ret += query_val2(a,b,rson),ret %= mod2;
        return ret;
    }
    void modify(int pos,int val,int root = 1){
        if(tree[root].l == tree[root].r){
            tree[root].valm = val;
            tree[root].val1 = (ll(val) * val) % mod1;
            tree[root].val2 = (ll(val) * val) % mod2;
            return;
        }
        if(pos <= mid)modify(pos,val,lson);
        else modify(pos,val,rson);
        maintain(root);
    }
    #undef lson
    #undef rson
}
using namespace ST;
inline int solve(ll x,ll n,ll k,ll mod){
    x %= mod,n %= mod,k %= mod;
    ll ret = 0;
    ret += ((ll(n) * x % mod) * x) % mod,ret %= mod;
    ret += (((ll(n) * (n - 1)  % mod) * k % mod) * x) % mod,ret %= mod;
    ret += (((((ll(k) * k  % mod) * n % mod) * (n - 1) % mod) * (2 * n - 1) % mod) * ((mod == 1e9 + 7) ? 166666668 : 833333341)) % mod,ret %= mod;
    return ret % mod;
}
inline bool check(int l,int r,int k){
    int x = query_min(l,r),n = r - l + 1;
    return (query_val1(l,r) == solve(x,n,k,mod1)) && (query_val2(l,r) == solve(x,n,k,mod2));
}
int n,m,cnt;
int main(){
    n = read(),m = read();
    for(int i = 1;i <= n;i++)val[i] = read();
    build(1,n);
    while(m--){
        if(int x,y,l,r,k;read() == 1){//if语句和switch语句内定义变量,其在else语句内也有效,是C++17的新特性
            x = read(),y = read();
            modify(x ^ cnt,y ^ cnt);
        }else{
            l = read(),r = read(),k = read();
            check(l ^ cnt,r ^ cnt,k ^ cnt) ? cnt++,printf("Yes\n") : printf("No\n");
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/colazcy/p/11515037.html

时间: 2024-10-08 17:44:07

题解 P5278 【算术天才⑨与等差数列】的相关文章

【BZOJ4373】算术天才⑨与等差数列 线段树+set

[BZOJ4373]算术天才⑨与等差数列 Description 算术天才⑨非常喜欢和等差数列玩耍.有一天,他给了你一个长度为n的序列,其中第i个数为a[i].他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序后能否形成公差为k的等差数列.当然,他还会不断修改其中的某一项.为了不被他鄙视,你必须要快速并正确地回答完所有问题.注意:只有一个数的数列也是等差数列. Input 第一行包含两个正整数n,m(1<=n,m<=300000),分别表示序列的长度和操作的次数.第二行

bzoj 4373 算术天才⑨与等差数列

4373: 算术天才⑨与等差数列 Time Limit: 10 Sec  Memory Limit: 128 MBhttp://www.lydsy.com/JudgeOnline/problem.php?id=4373 Description 算术天才⑨非常喜欢和等差数列玩耍.有一天,他给了你一个长度为n的序列,其中第i个数为a[i].他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序后能否形成公差为k的等差数列.当然,他还会不断修改其中的某一项.为了不被他鄙视,你必须要

【BZOJ4373】算术天才⑨与等差数列 [线段树]

算术天才⑨与等差数列 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 算术天才⑨非常喜欢和等差数列玩耍. 有一天,他给了你一个长度为n的序列,其中第i个数为a[i]. 他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序后能否形成公差为k的等差数列. 当然,他还会不断修改其中的某一项. 为了不被他鄙视,你必须要快速并正确地回答完所有问题. 注意:只有一个数的数列也是等

【BZOJ4373】算术天才⑨与等差数列

Description 算术天才⑨很喜欢和等差数列玩耍. 有一天,他给了你一个长度为n的序列,当中第i个数为a[i]. 他想考考你,每次他会给出询问l,r,k.问区间[l,r]内的数从小到大排序后是否能形成公差为k的等差数列. 当然,他还会不断改动当中的某一项. 为了不被他歧视,你必需要高速并正确地回答全然部问题. 注意:仅仅有一个数的数列也是等差数列. Input 第一行包括两个正整数n,m(1<=n,m<=300000),分别表示序列的长度和操作的次数. 第二行包括n个整数,依次表示序列中

BZOJ4373: 算术天才⑨与等差数列

Description 算术天才⑨非常喜欢和等差数列玩耍.有一天,他给了你一个长度为n的序列,其中第i个数为a[i].他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序后能否形成公差为k的等差数列.当然,他还会不断修改其中的某一项.为了不被他鄙视,你必须要快速并正确地回答完所有问题.注意:只有一个数的数列也是等差数列. Input 第一行包含两个正整数n,m(1<=n,m<=300000),分别表示序列的长度和操作的次数.第二行包含n个整数,依次表示序列中的每个数a[i

bzoj 4373: 算术天才⑨与等差数列 hash

题目链接 题目大意:  给你n个数, 给两种操作, 一种给你l, r, k,问你[l, r]区间里的数排序后能否构成一个公差为k的等差数列. 另一种是将位置x的数变为y. 强制在线. 可以用hash来做, 用线段树保存一个区间里的最小值, 和, 以及平方的和. 然后每次询问, 假设这个区间构成等差数列,那么首项为这个区间的最小值, 然后按公式算出以minn为首项, k为公差的数列的和, 为a1*len+len*(len-1)/2*d, 然后算出平方的和, 相当于sigma(i : 0 to le

AC日记——算术天才⑨与等差数列 bzoj 4373

4373 思路: 判断一个数列是否是等差数列: 1,最大值减去最小值==(区间个数-1)*k: 2,gcd==k: 3,不能有重复(不会这判断这一条,但是数据水就过了): 来,上代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 300005 struct TreeNodeType

bzoj4373:算数天才与等差数列

算术天才⑨非常喜欢和等差数列玩耍. 有一天,他给了你一个长度为n的序列,其中第i个数为a[i]. 他想考考你,每次他会给出询问l,r,k,问区间[l,r]内的数从小到大排序后能否形成公差为k的等差数列. 当然,他还会不断修改其中的某一项. 为了不被他鄙视,你必须要快速并正确地回答完所有问题. 注意:只有一个数的数列也是等差数列. 第一行包含两个正整数n,m(1<=n,m<=300000),分别表示序列的长度和操作的次数. 第二行包含n个整数,依次表示序列中的每个数a[i](0<=a[i]

#3316. baka

题目描述 Worldwide_D最近沉迷东方. 数学课上,Worldwide_D在研究对数,然后渐渐睡着了.他梦见自己躺在幻想乡的雾之湖边,听见旁边有两个妖精在对话,原来是Cirno和Daiyousei. Daiyousei:Cirno酱,我们趁着夜色,把整个幻想乡占领吧! Cirno:好啊!这样我们就可以到处玩了. 不知道你们反应如何,反正听到这段对话,Worldwide_D是笑出来了.幻想乡可以看作n个节点的树,每条道路都是有向边.Cirno可以消耗一点灵力,改变一条道路的方向. 如果最终得