【分块】 HDOJ 5286 wyh2000 and sequence

来源:互联网 发布:windows10壁纸软件 编辑:程序博客网 时间:2024/05/19 02:31

不错的分块题。。。附上BC的官方题解。。。

f(l,r)表示[l,r]的答案。我们对于序列分块,对于第i块,令Si为第i块的左端点。令g(a,b)表示第a块开头到第b块末尾这一段序列的答案。下面我们讨论如何求g(a,b)。我们枚举a,再枚举j(Sajn),考虑j 转移到j+1f(Sa,j)f(Sa,j+1)的关系。
f(Sa,j+1)=f(Sa,j)Asum(Aj+1)j+1+Asum(Aj+1)+1j+1
其中sum(x)表示x在区间[Sa,j]中出现的次数,这样我们就能用nnlogn的时间求出g(a,b)。令h(i,j)表示i在前j个块中出现的次数,这个也很容易用n的时间求出。考虑询问[l,r],两端的我们可以暴力求出来,中间的块内答案可以直接用g数组求出。然后我们可以用类似求g数组的方法将两端的数加入中间的块内。复杂度O(Qnlogn)。考虑到那个log为快速幂的复杂度,又因为每一个ab我们都可以发现a一定是序列中的数,b一定小于a在序列中出现的次数,所以我们可以O(n)预处理,用vector存起来即可。总复杂度O(nn+Qn)
#include <iostream>#include <queue>#include <stack>#include <map>#include <set>#include <bitset>#include <cstdio>#include <algorithm>#include <cstring>#include <climits>#include <cstdlib>#include <cmath>#include <time.h>#define maxn 50005#define maxm 305#define eps 1e-7#define mod 1000000007#define INF 0x3f3f3f3f#define PI (acos(-1.0))#define lowbit(x) (x&(-x))#define mp make_pair#define ls o<<1#define rs o<<1 | 1#define lson o<<1, L, mid #define rson o<<1 | 1, mid+1, R#define pii pair<int, int>#pragma comment(linker, "/STACK:16777216")typedef long long LL;typedef unsigned long long ULL;//typedef int LL; using namespace std;LL qpow(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base;base=base*base;b/=2;}return res;}LL powmod(LL a, LL b){LL res=1,base=a;while(b){if(b%2)res=res*base%mod;base=base*base%mod;b/=2;}return res;}// headvector<LL> vec[maxn];LL res[maxm][maxm];int C[maxm][maxn];LL a[maxn];LL b[maxn];int aa[maxn];int x[maxn];int c[maxn];int n, m;void work(){memset(C, 0, sizeof C);scanf("%d%d", &n, &m);for(int i = 0; i < n; i++) scanf("%lld", &a[i]), b[i] = a[i];sort(b, b+n);int cnt = unique(b, b+n) - b;for(int i = 0; i < n; i++) x[i] = lower_bound(b, b+cnt, a[i]) - b;for(int i = 0; i < cnt; i++) vec[i].clear();for(int i = 0; i < cnt; i++) vec[i].push_back(0);for(int i = 0; i < n; i++) {LL t = vec[x[i]][vec[x[i]].size() - 1];if(vec[x[i]].size() == 1) t = 1;t = t * a[i] % mod;vec[x[i]].push_back(t);}int s = sqrt(n), sn = n / s;if(n % s) sn++;LL ans = 0;for(int i = 0; i < sn; i++) {ans = 0;memset(c, 0, sizeof c);for(int j = i * s; j < n; j++) {int loc = j / s;ans = (ans - vec[x[j]][c[x[j]]] + vec[x[j]][c[x[j]] + 1] + mod) % mod;c[x[j]]++;res[i][loc] = ans;}}for(int i = 0; i < sn; i++)for(int j = 0; j < (i + 1)  * s && j < n; j++)C[i][x[j]]++;ans = 0;memset(c, 0, sizeof c);while(m--) {LL l, r, ll, rr;scanf("%lld%lld", &ll, &rr);l = min((ll ^ ans) % n, (rr ^ ans) % n);r = max((ll ^ ans) % n, (rr ^ ans) % n);ans = 0;int loc1 = l / s + 1;int loc2 = r / s - 1;if(loc2 >= loc1) ans = res[loc1][loc2];int tcnt = 0;if(l / s != r / s) {for(int i = l; i < loc1 * s; i++) aa[tcnt++] = x[i];for(int i = (loc2 + 1) * s; i <= r; i++) aa[tcnt++] = x[i];}else {for(int i = l; i <= r; i++) aa[tcnt++] = x[i];}for(int i = 0; i < tcnt; i++) {if(c[aa[i]] == 0 && loc2 >= loc1) c[aa[i]] += C[loc2][aa[i]] - (loc1 ? C[loc1-1][aa[i]] : 0);ans = (ans - vec[aa[i]][c[aa[i]]] + vec[aa[i]][c[aa[i]] + 1] + mod) % mod;c[aa[i]]++;}for(int i = 0; i < tcnt; i++) c[aa[i]] = 0;printf("%lld\n", ans);}}int main(){int _;scanf("%d", &_);while(_--) work();return 0;}


0 0