hdu 3486 Interviewe RMQ
//hdu 3486 Interviewe //RMQ //用RMQ预处理一下,然后进行枚举,具体看代码 //枚举要加优化,要不一样会超时 #define infile freopen("in.txt", "r", stdin); #include <stdio.h> #include <string.h> #define INF (1<<30) #define N 200005 int dp_max[20][N], log2[N]; inline int max(const int a, const int b) { return a > b? a : b; } void rmq(int n) { for(int i = 1; i <= log2[n]+1; ++i)//从第j个开始2^i个数,所以要减1 for(int j = 1; j + (1<<i) - 1 <= n; ++j)//这里中间那个一定要减1,wa了好多次 dp_max[i][j] = max(dp_max[i-1][j], dp_max[i-1][j+(1<<(i-1))]); //j+(1<<i)-1 减1表示从第j个起的2^i个,包括j所以要减 1 } int get_max(int from, int to) { int index = log2[to-from+1]; return max(dp_max[index][from], dp_max[index][to-(1<<index)+1]); } int find(int n, int low) //枚举 { int pre_num = -1, pre_tot = -1, pre_sum; for(int i = 1; i <= n; ++i) //分成i组 { int num = n / i; //每组num个 int sum = num * i; //总的多少人 int tot = 0; if(num == pre_num) //如果和前一次一样则从前一次继续累加即可 { tot = pre_tot; for(int j = pre_sum + num; j <= sum; j+= num) { tot += get_max(j - num + 1, j); if(tot > low) return i; } pre_tot = tot; pre_sum = sum; } else { for(int j = num; j <= sum; j += num) { tot += get_max(j-num+1, j); if(tot > low) return i; } pre_num = num; pre_tot = tot; pre_sum = sum; } } return -1; } int main() { //infile int n, low; for(int i = 2; i < N; ++i) log2[i] = (i&(i-1)) == 0 ? log2[i-1]+1 : log2[i-1]; while(scanf("%d%d", &n, &low), n > 0 || low > 0) { memset(dp_max, 0, sizeof(dp_max)); for(int i = 1; i <= n; ++i) scanf("%d", &dp_max[0][i]); rmq(n); printf("%d\n", find(n, low)); //一下二分是错的 wa了,下面这组数据答案应该是2,可以卡死 //但别人这组数据过不了也a了,估计我的二分写错了 //10 1500 //1 1 1 1 1000 1000 1 1 1 1 // int l = 1, h = n; // bool flag = false; // while(l < h) // { // int mid = l + (h-l)/2; // int num = n / mid, sum = 0; // for(int i = 0; i < mid; ++i) // sum += get_max(i*num+1, (i+1)*num); // if(sum > low) // { // flag = true; // h = mid; // } // else // l = mid + 1; // } // if(l == h && flag == true) // printf("%d\n", l); // else // puts("-1"); } return 0; }
二杰的二分
#include <stdio.h> #include <string.h> const int N = 200005; int log2[N]; int rmqMax[N][20];//表示从i到i+(2^j)-1最大的值 void init() { log2[1] = log2[0] = 0; for(int i = 2; i < N; ++i) { log2[i] = log2[i-1]; if(((i-1)&i) == 0) log2[i]++; } } inline int max(const int a, const int b) { return a > b? a : b; } inline int query(int a, int b) { int k = log2[(b-a)+1]+1; return max(rmqMax[a][k-1], rmqMax[b-(1<<(k-1))+1][k-1]); } int getAns(int key, int step) { int ans = 0; for(int i = 1; i+step-1 <= step*key; i += step) { ans += query(i, i+step-1); } return ans; } int binaryFind(int left, int right, int k, int n) { int tt = 0; for(int i = 1; i <= n; ++i) tt += rmqMax[i][0]; if(tt <= k) return -1; int mid; //对组数二分,不是对每组多少人二分 while(left != right) { mid = (left+right)/2; int num = n/mid; int ans = getAns(mid,num); if(ans > k) right = mid; else left = mid+1; } return right; } int main(void) { // comein int n, k; init(); while(scanf("%d%d", &n, &k) == 2 && n>0 && k>0) { for(int i = 1; i <= n; ++i) { scanf("%d", &rmqMax[i][0]); } for(int j = 1; j < 20; ++j) { for(int i = 1; i+(1<<(j-1)) <= n; ++i) { rmqMax[i][j] = max(rmqMax[i][j-1], rmqMax[i+(1<<(j-1))][j-1]); } } // int a, b; // while(scanf("%d%d", &a, &b) == 2) // { // int ans = query(a, b); // printf("%d\n", ans); // } int ans = binaryFind(1, n, k, n); printf("%d\n", ans); } return 0; }