题目 poj2887
这个题我一看是1e6 并且多次查询,第一想到的是树状数组和线段树,因为是多次查询嘛,但是这个题查询的复杂度是1,但是字符串拼接的复杂度却是1e6
这个题我当时感觉是分桶法了,分桶法的目的就是提前能够判断某个数在哪个区间,并在这个区间中去寻找,
分开管理每个桶里面装的字符
之后查了一下有其他的名字,叫区块数组
思想都是一样的,放进不同的桶中,每个桶中记录包含的元素个数和元素,每次插入一个元素,总共也就最多插到3000个,所以不用担心插得元素过多,导致插入时间增加过多
#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> using namespace std; const int N = 1e3+3; int str[N][N*3]; //这个就是区块数组 int l[N]; //每个桶的长度或者叫大小 int num; //一共有多少个桶 char query(int x) { int cnt = 0; //cnt用于记录前面的桶一共装了多少元素 int i; for(i=0; i<num; ++i) { if(cnt + l[i] >= x) break; cnt += l[i]; } return str[i][x-cnt-1]; } void inser(char c,int x) { int cnt = 0,i,pn,j; for(i = 0; i < num; ++i) { if(cnt + l[i] >= x) { pn = i; break; } else if(i == num-1) { pn = num-1; break; } cnt += l[i]; } int k = x - cnt; for(j = l[i]; j >= k; --j) str[i][j] = str[i][j-1]; str[i][j] = c; } void init(char *s) //初始化桶中的元素 { int len = strlen(s); int n = (len+999)/1000; int j = 0,i,k; int cnt; for(i=0; i<n && j<len; ++i) { cnt = 0; for(k = 0;k<1000 && j<len; ++k) { str[i][k] = s[j++]; l[n]=cnt++;; } } }