[SGU 177]利用并差集处理矩形覆盖问题**

【题目大意】给定一个N*N的矩阵和M次染色,问最后是白色的格子还有多少个?

【算法分析】这题一看是线段树or矩形切割,但是仔细一想,可以发现一种新的算法,这中间利用了并差集。定义next[i,j]表示如果要染i,j这一个格子的话,应当去染哪一个格子。考虑我们写矩形切割的“浮冰法”,从后面开始进行insert,这样的话,后insert的必须避开先insert得。所以可以利用这个next进行跳跃。我这个next只针对当前行,就是next[i,j]的跳跃位置是对于第i行而言的。

初始时next[i,j]=j,表示要染这一格,那么就应该染这一格,比较拗口

然后如果对这一格被染色的话,那么next[i,j]=j+1,这样下一次就会越过我跳到下一格了,然后用并差集进行路径压缩,这样就能在平摊O(1)的复杂度调到下一个能染得格了!

这个算法中,对每个格子最多碰一次,所以染色的复杂度为O(N^2),但是由于对于每一次染色,都必须枚举行,所以总复杂度是O(N^2+NM)。

【其它】1A,时限7S

997757 09.02.10 16:53 edward 177 .CPP Accepted 796 ms 9739 kb

【CODE】

#include #include const int N=1111;
const int M=5555;
int n,m,next[N][N],x1[M],x2[M],y1[M],y2[M],color[N][N],dc[M];

void swap(int &x,int &y){
    int tmp=x; x=y; y=tmp;
}   

void init(){
    for (int i=0;i<=n+1;i++)
      for (int j=0;j<=n+1;j++)
        next[i][j]=j;
}   

int findnext(int i,int j){
    if (next[i][j]==j) return j;
    next[i][j]=findnext(i,next[i][j]);
    return next[i][j];
}   

void work(){
    memset(color,200,sizeof(200));
    for (int tmp=m;tmp>=0;tmp–)
      for (int i=x1[tmp];i<=x2[tmp];i++){
          for (int j=y1[tmp];j<=y2[tmp];)
            if (next[i][j]==j){
                color[i][j]=dc[tmp];
                next[i][j]=j+1;
                j++;
            }
            else j=findnext(i,j);
      }
}   

void print(){
    int ans=0;
    for (int i=1;i<=n;i++)
      for (int j=1;j<=n;j++)
        if (color[i][j]==0) ans++;
    printf("%dn",ans);
}   

int main(){
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    scanf("%d%d",&n,&m);
    x1[0]=1; y1[0]=1; x2[0]=n; y2[0]=n;
    for (int i=1;i<=m;i++){
        int lx,ly,rx,ry;
        char co;
        scanf("%d%d%d%d %c",&lx,&ly,&rx,&ry,&co);
        if (lx>rx) swap(lx,rx);
        if (ly>ry) swap(ly,ry);
        x1[i]=lx; x2[i]=rx; y1[i]=ly; y2[i]=ry;
        if (co==’b’) dc[i]=1;
    }   
    init();
    work();
    print();
    return 0;
}   

[POJ 2029]矩阵处理

【题目大意】给定N*M的矩形和T个点,让你求A*B的子矩形最多能覆盖几个点。

【算法分析】压缩列,再扫描行。这个方法是O(N^3)的,最快的算法请参见这道题的加强版:http://hi.baidu.com/edwardmj/blog/item/b2ffc2f83570dd9d59ee900a.html

【其它】1A

6429770 edward2 2029 Accepted 508K 16MS G++ 924B 2010-02-09 20:40:21

【CODE】

#include

[POJ 1019]数字处理

【题目大意】有这样一个序列,1,112,112123,1121231234,112123123412345…,求它的第X位是多少。

【算法分析】

构造,分步骤来求,逐步逼近答案。

先对序列进行分组,即按1,12,123,1234,12345这样分组,利用递推求出前I组数的位数,即Sum[I]:=Sum[I-1]+F[I],F[I]:=F[I-1]+Trunc(ln(I)/ln(10))+1。

这样,我们可以很容易确定第X位的所在组(当组大于40000时,位数已经超过Maxlongint)

然后在用While循环求出第X位是这个组中的第几个数,再求出是这个数的第几位即可。

【其它】复杂度约为O(sqrt(n))

6429639 edward2 1019 Accepted 884K 16MS G++ 1094B 2010-02-09 20:10:37

【CODE】

#include

[POJ 2019]矩阵处理

【题目大意】给定一个N*N的矩阵和K个询问,对于每个询问输出以该坐标为左上角的B*B的子矩阵中,最大值-最小值是多少?

【算法分析】先预处理把列压缩,然后再利用枚举打表,最后直接输出。

【其它】1A。时间复杂度O(N^3)

6429453 edward2 2019 Accepted 1036K 219MS G++ 1117B 2010-02-09 19:08:19

【CODE】

#include

[POJ 2299]逆序对

【题目大意】给定一种操作:交换两个相邻的数。问最少操作多少次,可以使得给定的序列不降序。

【算法分析】其实就是逆序对。为什么呢?因为每次有效操作,必然把两个位置不对的数交换,这样就相当于搞定了其中一个逆序对,所以最后答案就是逆序对的个数。

【其它】1A

6429266 edward2 2299 Accepted 4100K 391MS G++ 603B 2010-02-09 18:16:14

【CODE】

#include