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 len-1) (a1+i*d)^2, 然后把它拆开, 就变成a1*a1*len+a1*d*len*(len-1)+d*d*len*(len-1)*(2*len-1)/6, 记得时刻取模防止爆longlong, /6那里用乘法逆元算。 然后看是否相等就可以了。

正解当然不是这样的..

#include <iostream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <string>
#include <queue>
#include <stack>
#include <bitset>
using namespace std;
#define pb(x) push_back(x)
#define ll long long
#define mk(x, y) make_pair(x, y)
#define lson l, m, rt<<1
#define mem(a) memset(a, 0, sizeof(a))
#define rson m+1, r, rt<<1|1
#define mem1(a) memset(a, -1, sizeof(a))
#define mem2(a) memset(a, 0x3f, sizeof(a))
#define rep(i, n, a) for(int i = a; i<n; i++)
#define fi first
#define se second
typedef pair<int, int> pll;
const double PI = acos(-1.0);
const double eps = 1e-8;
const ll mod = 1e9+7;
const ll inf = 1e18;
const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
const int maxn = 3e5+5;
ll sum1[maxn<<2], sum2[maxn<<2], minn[maxn<<2], ans1, ans2, ans3;
void pushUp(int rt) {
    sum1[rt] = sum1[rt<<1]+sum1[rt<<1|1];
    sum2[rt] = (sum2[rt<<1] + sum2[rt<<1|1])%mod;
    minn[rt] = min(minn[rt<<1], minn[rt<<1|1]);
}
void build(int l, int r, int rt) {
    if(l == r) {
        scanf("%I64d", &sum1[rt]);
        minn[rt] = sum1[rt];
        sum2[rt] = sum1[rt]*sum1[rt]%mod;   
        return ;
    }
    int m = l+r>>1;
    build(lson);
    build(rson);
    pushUp(rt);
}
void update(int p, ll val, int l, int r, int rt) {
    if(l == r) {
        sum1[rt] = minn[rt] = val;
        sum2[rt] = val*val%mod;
        return ;
    }
    int m = l+r>>1;
    if(p<=m)
        update(p, val, lson);
    else
        update(p, val, rson);
    pushUp(rt);
}
void query(int L, int R, int l, int r, int rt) {
    if(L<=l&&R>=r) {
        ans1 += sum1[rt];
        ans2 = (ans2+sum2[rt])%mod;
        ans3 = min(ans3, minn[rt]);
        return ;
    }
    int m = l+r>>1;
    if(L<=m)
        query(L, R, lson);
    if(R>m)
        query(L, R, rson);
}
ll pow(ll a, ll b) {
    ll ret = 1;
    while(b) {
        if(b&1) {
            ret = ret*a%mod;
        }
        a = a*a%mod;
        b>>=1;
    }
    return ret;
}
ll get1(ll a1, ll l, ll d) {
    ll ret = a1*l+l*(l-1)/2*d;
    return ret;
}
ll get2(ll a1, ll l, ll d) {
    ll ret = a1*a1%mod*l%mod;
    ll rev = pow(6LL, mod-2)%mod;
    ret = (ret + d*d%mod*l%mod*(l-1)%mod*(2*l-1)%mod*rev%mod)%mod;
    ret = (ret + a1*d%mod*l%mod*(l-1)%mod)%mod;
    return ret%mod;
}
int main()
{
    int n, m, cnt = 0, sign, x, y, z;
    cin>>n>>m;
    build(1, n, 1);
    while(m--) {
        scanf("%d%d%d", &sign, &x, &y);
        x ^= cnt, y ^= cnt;
        if(sign == 1) {
            update(x, 1LL*y, 1, n, 1);
        } else {
            scanf("%d", &z);
            z ^= cnt;
            ans3 = inf, ans1 = ans2 = 0;
            query(x, y, 1, n, 1);
            ll tmp1 = get1(ans3, y-x+1, z);
            ll tmp2 = get2(ans3, y-x+1, z);
            if(tmp1 == ans1 && tmp2 == ans2) {
                cnt++;
                puts("Yes");
            } else {
                puts("No");
            }
        }
    }
    return 0;
}

 

posted on 2016-02-25 23:25  yohaha  阅读(352)  评论(0编辑  收藏  举报

导航