pcfeng502

Brown's Space
 
 

常用链接

  • 我的随笔
  • 我的评论
  • 我参与的随笔

留言簿

  • 给我留言
  • 查看公开留言
  • 查看私人留言

随笔档案

  • 2010年10月 (1)
  • 2010年4月 (2)
  • 2009年11月 (3)
  • 2009年10月 (3)
  • 2009年9月 (3)
  • 2009年8月 (1)
  • 2009年7月 (1)

文章档案

  • 2009年5月 (1)

搜索

  •  

最新评论

  • 1. re: 求2的n次方的首数字
  • 写错了 是le-8
  • --baby
  • 2. re: 求2的n次方的首数字
  • int ans = (int) (pow(10.0, t-(double)y));
    取整的地方 +1e8
  • --baby

阅读排行榜

  • 1. poj 1042 -- Gone Fishing 枚举+贪心(1201)
  • 2. Poj 3370 Halloween treats(1168)
  • 3. 求2的n次方的首数字(989)
  • 4. poj 1442 Black box(927)
  • 5. C++ 标准库中函数所对应的头文件(转)(835)

评论排行榜

  • 1. 求2的n次方的首数字(2)
  • 2. C++ 标准库中函数所对应的头文件(转)(0)
  • 3. poj 1442 Black box(0)
  • 4. Poj 3370 Halloween treats(0)
  • 5. Poj 1597 – Uniform Generator 数论基础题(欢迎评论)(0)

Powered by: 博客园
模板提供:沪江博客
C++博客 | 首页 | 发新随笔 | 发新文章 | 联系 | 聚合 | 管理

3264 -- Balanced Lineup RMQ

3264 -- Balanced Lineup

 

很裸的一道RMQ题目,开始不知道Sparse Table怎么写,后面问了之后才知道是用二进制的思想,用DP的方法的方法求出。

 

Sparse Table其实就相当于一个高效的打表方法(算法时间&&空间复杂度为O(nlogn)),我们设f(i, j)表示[i, i+2j-1]区间中的最小值,即

         f(0, 0)表示[0, 0]中的最小值

         f(0, 2)表示[0, 3]中的最小值

         f(2, 4)表示[2, 17(2+16-1)]中的最小值

         ………………

在做最值的稀疏表(Sparse Table)时,因为是自顶向下推理,要注意循环嵌套的顺序

其中j从0→log2(n)                            //j = 0 的情况,将f(i, 0) 初始化为 d[i]

         i从0→i+2j-1 < n

                   求最值f[i][j]:具体参考程序

 

打完了Sparse Table之后,假设我们要找[a, b]区间中的最小值,则我们

1先求出一个最大的k,使得(b – a +1) > 2k

这样就能把[a, b]分成两个(部分重叠的)长度为2k的空间

         2所以要求[a, b]的最小值,只需返回(因为前面求了的)[m, m+2k-1]和[n-2k+1, n]中的最小值即可,算法复杂度为O(n)。

 

对于i从0开始还是从1开始,其实这个无所谓,从0开始的话,只需将每个question中的位置-1即可,而且跟符合C中编程思想一些。

 

#include <iostream>

#include <cstring>

#include <cmath>

using namespace std;

#define maxs(a, b)   ((a>b)?(a):(b))

#define mins(a, b)    ((a<b)?(a):(b))

 

const int MAXN = 50010;

int d[MAXN];

int dpmin[MAXN][17];

int dpmax[MAXN][17];     //2^16 = 65536 > 50000

int n, q;

 

void createDpmin() {

         int i, j, k;

         // initial situation: j = 0;

         for (i = 0; i < n; i++)

                   dpmin[i][0] = d[i];     //递推的初值:一个数的最值肯定是自己

         //bottom-top approach: so j is in the outer loop

         for (j = 1; j <= log((double)(n))/log(2.0); j++){

                   for (i = 0; i+(1<<j)-1 < n; i++) {

                            dpmin[i][j] = mins(dpmin[i][j-1], dpmin[i+(1<<(j-1))][j-1]);

                   }

         }

}

 

void createDpmax() {

         int i, j;

         for (i = 0; i < n; i++)

                   dpmax[i][0] = d[i];

         for (j = 1; j <= log((double)(n))/log(2.0); j++) {

                   for (i = 0; i+(1<<j)-1 < n; i++) {

                            dpmax[i][j] = maxs(dpmax[i][j-1], dpmax[i+(1<<(j-1))][j-1]);

                   }

         }

}

 

 

void initi() {

         createDpmin();

         createDpmax();

         //dump(n);

}

 

int rminq(int a, int b) {

         int k = (int)(log((double)(b - a + 1))/log(2.0));

         return mins(dpmin[a][k], dpmin[b-(1<<k)+1][k]);

}

 

int rmaxq(int a, int b) {

         int k = (int)(log((double)(b - a + 1))/log(2.0));

         return maxs(dpmax[a][k], dpmax[b-(1<<k)+1][k]);

}

 

int main() {

         int i;

         int a, b;

         int ans;

         while (scanf("%d %d", &n, &q) != EOF) {

                   for (i = 0; i < n; i++)

                            scanf("%d", &d[i]);

                   initi();

                   while(q--) {

                            scanf("%d %d", &a, &b);

                            ans = rmaxq(a-1, b-1) - rminq(a-1, b-1);

                            printf("%d\n", ans);

                   }

         }

         return 0;

}

posted @ 2009-09-18 15:17 ACM Fighter! 阅读(158) | 评论 (0) | 编辑 收藏
 
poj 1042 -- Gone Fishing 枚举+贪心

Gone Fishing

       这道题其实难在读题上,因为这道题的细节太多,往往容易搞混,造成WA的情况,所以,学好英语还是有作用的。

 

       解此题的主要方法是枚举+贪心。刚开始的时候还没想到一个好方法,因为当前鱼最多的池塘是变化的,而题目所给描述里面的钓鱼又是有顺序的,即:John starts at lake 1, but he can finish at any lake he wants. He can only travel from one lake to the next one, but he does not have to stop at any lake unless he wishes to.所以,不可能在池塘中间瞬移,所以贪心貌似不能用。

 

       但转念一想,瞬移还是有可能的,当确定了结束池塘ep(endpond)之后(结束池塘由1枚举到n),我们便可以把从1到ep的交通费用从h中减去,然后用剩下的时间贪心即可。因为在分析问题时,对于一个池塘,John在它上面什么时候钓鱼并不重要,所以可以先把John看成很聪明的人,然后假设他已经知道了在确定了结束池塘后,在每个池塘花多少时间使收益最大(实际上John是在贪心之后才知道的),这时我们就可以先减去交通费用,然后在1~ep的池塘中找现在的最大的即可。

 

       这道题还比较容易WA,但最容易WA的地方还是全零的情况。


#include <iostream>

using namespace std;
int const MAXP = 31;
int n, h, tt;
int f[MAXP], d[MAXP], t[MAXP];
int a[MAXP], res[MAXP];
int cf[MAXP];
int ans;

void initi() {
    fill(f, f
+MAXP, 0);
    fill(d, d
+MAXP, 0);
    fill(t, t
+MAXP, 0);
    fill(a, a
+MAXP, 0);
    fill(res, res
+MAXP, 0);
    ans 
= -1;
}

int readIn() {
    
int i, j;
    scanf(
"%d", &n);
    
if (n == 0) return 0;
    scanf(
"%d", &h);
    tt 
= h * 12;
    
for (i = 0; i < n; i++)
        scanf(
"%d", &f[i]);
    
for (i = 0; i < n; i++)
        scanf(
"%d", &d[i]);
    
for (i = 0; i < n-1; i++)
        scanf(
"%d", &t[i]);
    
return 1;
}

void process() {
    
int curtt, curfish;
    
int i, j, ep; //    ep stands for end pond
    int tmpmf, tmpp;
    
for (ep = 0; ep < n; ep++) {
        curtt 
= tt; curfish = 0;
        fill(a, a
+MAXP, 0);
        
for (i = 0; i < ep; i++) {
            curtt 
-= t[i];
            cf[i] 
= f[i];
        }
        cf[ep] 
= f[ep];
        
        
for (i = 0; i < curtt; i++) {
            tmpmf 
= -1; tmpp = 0;
            
for (j = 0; j <= ep; j++)
                
if (tmpmf < cf[j]) {
                    tmpmf 
= cf[j];
                    tmpp 
= j;
                }
            a[tmpp]
++;
            curfish 
+= tmpmf;
            cf[tmpp] 
= max(0, cf[tmpp] - d[tmpp]);
        }
        
        
if (curfish > ans) {
            ans 
= curfish;
            
for (i = 0; i < n; i++) {
                res[i] 
= a[i];
            }
        }
    }
}

void printAns() {
    
int i;
    
for (i = 0; i < n; i++)
        res[i] 
*= 5;

    printf(
"%d", res[0]);
    
for (i = 1; i < n; i++)
        printf(
", %d", res[i]);
    printf(
"\n");
    printf(
"Number of fish expected: %d\n\n", ans);
}

int main() {
    initi();
    
while (readIn()) {
        process();
        printAns();
        initi();
    }
    
return 0;
}

posted @ 2009-08-15 10:24 ACM Fighter! 阅读(1201) | 评论 (0) | 编辑 收藏
 
USACO -- S2.3 Cow Pedigrees

S2.3 Cow Pedigrees

This is a typical DP problem. Since all the trees have either two children or none, we know that all trees with depth i can be built upon those ones with depth i+1. And this is crucial to solving this problem.

 

We define table[i][j] as the number of legal trees with depth i and j nodes. There are 3 possibilities to build a i-depth tree.

1.       The left subtree’s depth is i-1  while  the right one’s smaller than i-1;

2.       The left subtree’s depth is small than i-1  while  the right one’s i-1;

3.       Both the left and the right subtrees’ depth are i-1.

 

According what we have analysed. We can define another 2-dimensional array smalltrees[i][j] to restore all the sum of trees shorter than i—from 1 to i-1—to avoid unnecessary loops when calculating. Thus, we got:

 

(k loops from 1 to j, increment is 1, indicating the nodes of the left subtree)

Table[i][j] += table[i-1][k] * smalltrees[i-2][j-k-1];

Table[i][j] += smalltrees[i-2][k] * table[i-1][j-k-1];

Table[i][j] += table[i-1][k] * table[i-1][j-k-1]. ①

 

And remember to refresh smalltrees every time:

(k indicate the depth of the tree)

smalltrees[i-1][k] += table[i-1][k] + smalltrees[i-2][k]. ①

 

①:After getting each value, mod process is needed.

posted @ 2009-07-14 16:00 ACM Fighter! 阅读(249) | 评论 (0) | 编辑 收藏
 
仅列出标题
共2页: 1 2