zoukankan      html  css  js  c++  java
  • 【线段树 集合hash】bzoj4373: 算术天才⑨与等差数列

    hash大法好(@ARZhu);大数相乘及时取模真的是件麻烦事情

    Description

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

    Input

    第一行包含两个正整数n,m(1<=n,m<=300000),分别表示序列的长度和操作的次数。
    第二行包含n个整数,依次表示序列中的每个数a[i](0<=a[i]<=10^9)。
    接下来m行,每行一开始为一个数op,
    若op=1,则接下来两个整数x,y(1<=x<=n,0<=y<=10^9),表示把a[x]修改为y。
    若op=2,则接下来三个整数l,r,k(1<=l<=r<=n,0<=k<=10^9),表示一个询问。
    在本题中,x,y,l,r,k都是经过加密的,都需要异或你之前输出的Yes的个数来进行解密。

    Output

    输出若干行,对于每个询问,如果可以形成等差数列,那么输出Yes,否则输出No。

    Sample Input

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

    Sample Output

    No
    Yes

    题目分析

    动态询问区间是否为「等差数列」。出题人用线段树维护了区间最小;区间gcd;区间……等等一系列标记。

    然而HZQ给出了一个吊打出题人的做法:线段树hash。

    注意到询问的区间可以视作集合形式,与顺序无关。于是便可以快速地集合hash。

    具体来说用线段树维护区间最小值(用于寻找等差数列首项);区间立方和(由费马大定理得立方和不容易被卡;不过在这题出题人并没有恶意卡平方哈希)

    问题就在于如何快速验证;换句话说就是计算询问的等差数列的hash值$x^3+(x+k)^3+(x+2*k)^3+...+(x+(n-1)*k)^3$其中$n$为序列长度

    把式子按照指数展开,就可以愉快地$O(1)$计算数列答案了。我才没有暴力展开算了1h什么都没算出来

      1 #include<bits/stdc++.h>
      2 typedef long long ll;
      3 const ll MO = 1e9+7;
      4 const int INF = 2e9;
      5 const int maxn = 300035;
      6 
      7 int n,m,preans;
      8 ll mn[maxn<<2],f[maxn<<2];
      9 
     10 int read()
     11 {
     12     char ch = getchar();
     13     int num = 0;
     14     bool fl = 0;
     15     for (; !isdigit(ch); ch = getchar())
     16         if (ch=='-') fl = 1;
     17     for (; isdigit(ch); ch = getchar())
     18         num = (num<<1)+(num<<3)+ch-48;
     19     if (fl) num = -num;
     20     return num;
     21 }
     22 ll qmi(ll a, ll b)
     23 {
     24     ll ret = 1;
     25     while (b)
     26     {
     27         if (b&1) ret = ret*a%MO;
     28         a = a*a%MO, b >>= 1;
     29     }
     30     return ret;
     31 }
     32 void pushup(int rt)
     33 {
     34     mn[rt] = std::min(mn[rt<<1], mn[rt<<1|1]);
     35     f[rt] = (f[rt<<1]+f[rt<<1|1])%MO;
     36 }
     37 void build(int rt, int l, int r)
     38 {
     39     mn[rt] = INF;
     40     if (l==r){
     41         mn[rt] = f[rt] = read();
     42         f[rt] = 1ll*f[rt]*f[rt]%MO*f[rt]%MO;
     43         return;
     44     }
     45     int mid = (l+r)>>1;
     46     build(rt<<1, l, mid), build(rt<<1|1, mid+1, r);
     47     pushup(rt);
     48 }
     49 void update(int rt, int l, int r, int pos, ll c)
     50 {
     51     if (l==r){
     52         f[rt] = c*c%MO*c%MO, mn[rt] = c;
     53         return;
     54     }
     55     int mid = (l+r)>>1;
     56     if (pos <= mid) update(rt<<1, l, mid, pos, c);
     57     else update(rt<<1|1, mid+1, r, pos, c);
     58     pushup(rt);
     59 }
     60 int queryMn(int rt, int L, int R, int l, int r)
     61 {
     62     if (L <= l&&r <= R) return mn[rt];
     63     int mid = (l+r)>>1, ret = INF;
     64     if (L <= mid)
     65         ret = queryMn(rt<<1, L, R, l, mid);
     66     if (R > mid) ret = std::min(ret, queryMn(rt<<1|1, L, R, mid+1, r));
     67     return ret;
     68 }
     69 ll query(int rt, int L, int R, int l, int r)
     70 {
     71     if (L <= l&&r <= R) return f[rt]%MO;
     72     int mid = (l+r)>>1;
     73     ll ret = 0;
     74     if (L <= mid) ret = query(rt<<1, L, R, l, mid);
     75     if (R > mid) ret += query(rt<<1|1, L, R, mid+1, r);
     76     return ret%MO;
     77 }
     78 ll calc(ll x, ll n, ll k)
     79 {
     80     ll ret = n*x%MO*x%MO*x%MO, pos = 1ll*n*(n-1)%MO*qmi(2, MO-2)%MO;
     81     ret += ((k*k%MO*k%MO*pos%MO*pos%MO+3*k%MO*x%MO*x%MO*pos%MO)%MO+k*x%MO*k%MO*(2*n-1)%MO*pos%MO)%MO;
     82     return ret%MO;          //时刻记得要取模!
     83 }
     84 int main()
     85 {
     86 //    freopen("4373.in","r",stdin); 
     87 //    freopen("4373.out","w",stdout);
     88     n = read(), m = read();
     89     build(1, 1, n);
     90     for (int i=1; i<=m; i++)
     91     {
     92         int opt = read();
     93         if (opt==1){
     94             int x = read()^preans, y = read()^preans;
     95             update(1, 1, n, x, y);
     96         }else{
     97             int l = read()^preans, r = read()^preans, k = read()^preans, lens = (r-l+1);
     98             int st = queryMn(1, l, r, 1, n);
     99             ll sum = query(1, l, r, 1, n);
    100             if (calc(st, lens, k)==sum) preans++, puts("Yes");
    101             else puts("No");
    102         }
    103     }
    104     return 0;
    105 }

    END

  • 相关阅读:
    常见英语缩写Abbreviations
    Outlook2016邮件如何设置靠右的预览窗格/Reading Pane?
    Power BI Server的SharePoint Credentials设置,OAuth2 + None
    Power BI 怎么定时同步自己电脑上的数据,并在Power BI server上定时刷新报表?
    Black Unique 全球购骑士卡 吃喝玩乐全有折扣
    怎么导出、同步OneNote上面的笔记到另一台电脑的解决方案
    Spring Cloud Gateway 网关内置API
    Spring Cloud Gateway 过滤器
    Spring Cloud Gateway 路由谓词工厂
    Spring Cloud Gateway 路由定位器
  • 原文地址:https://www.cnblogs.com/antiquality/p/9364412.html
Copyright © 2011-2022 走看看