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; }