P1005 [矩阵取数游戏]

生平第一次独立做出和省选沾边的题,发个题解记录一下♪(^∀^●)ノ

和大部分题解一样,用到了dp思想:区间(l,r)可以由左面取得一个数字{(l-1.r)},或者是右面取一个数字{(l,r+1)}获得,取两者之间的最大值即为最优解。

因此伪代码如下:

如果 l不是区间的左边界( 1 )
	那么就可以由左面推过来
    ans1=f[l-1][r]+num[l-1]*2(的倍数)
    
如果 r不是区间的右边界( m )
	那么就可以由右面推过来
    ans2=f[l][r+1]+num[r+1]*2(的倍数)
    
 f[l,r]=max(ans1,ans2);

那么程序就可以出炉了。

但是,这么做只能得到60分,因为数据限制,我们需要用到高精度才能ac

我看到很多题解提到了int128这么一个玩意儿,但是发现我的编译器(dev)居然不认,而且网上查了查资料感觉这个玩意儿并不是善茬...

仔细观察题意,发现每一次的得分都必定是2的倍数。那么...就可以模拟一下二进制。

开了201个数组(防止re嘛,具体多少我也没算),利用类似于快速幂的思想,若当前要假如一个x*2^m,那么只需要从第m+1的位置(因为二进制里第一位是2^0)开始,将x打成二进制,每一次都x>>=1向右滚动,滚动了n位之后,当x&1==1了,那么就把数组的m+n+1位++。

如此一来,只需要在最后一次输出时,将得到的二进制数转化为一个高精度十进制数,输出答案即可。

这里,有几点我做题时被坑了,汇总一下:

  1. 采用这种处理方法可能会导致二进制数组的某一位置的值>=2,因此不能贪空间而开bool型数组,并且每一次操作后都要检查一遍,将>=2的数位向上进位

  2. 在最终输出答案的时候,要特判一下长度是否为零。否则可能因为答案就是0,但长度认为0而不输出任何结果。(我就因为这个原因得了90分,第一个点wa了)

  3. 二进制的第一位是2^0因此加一个数字的时候,例如x*2^m,一定要从m+1开始!

  4. 各种杂七杂八的进位处理问题,只能说处理的时候要小心.千万小心!当你惆怅了半天查不出bug,结果发现把+=写成++了,那感觉......

最后附上代码,第一次发题解,长度拿捏不好
( # ▽ # )

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;

int n,m,num[81][81],ans[201],ansp[201],f[81][81][201];

void work(int[]);
void adjust(int[]);
void intcpy(int[],int[]);
int intcmp(int[],int[]);
void intplus(int[],int[]);
void print(int[]);

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            scanf("%d",&num[i][j]);
        }
    }
    for(int i=1;i<=n;++i){
        work(num[i]);
        intplus(ans,ansp);
        adjust(ans);
    }
    print(ans);
    return 0;
}

void work(int x[]){
    memset(f,0,sizeof(f));
    for(int i=1;i<=m;++i){
        for(int j=m;j>=i;--j){
            //怀疑是不是cnt的鬼m-j+i; 
            int cnt=m-j+i,ans1[201]={0},ans2[201]={0};
            //if(i>1) f[i][j]=max(f[i][j],f[i-1][j]+x[i-1]*cnt);
            if(i>1){
                intcpy(ans1,f[i-1][j]);
                int tmpcnt=cnt,plust=x[i-1];
                while(plust){
                    if(plust&1){
                        ans1[tmpcnt]++;
                    }
                    tmpcnt++;plust>>=1;
                }
                adjust(ans1);
            }
            //if(j<m) f[i][j]=max(f[i][j],f[i][j+1]+x[j+1]*cnt);
            if(j<m){
                intcpy(ans2,f[i][j+1]);
                int tmpcnt=cnt,plust=x[j+1];
                while(plust){
                    if(plust&1){
                        ans2[tmpcnt]++;	
                    }
                    tmpcnt++;plust>>=1;
                }
                adjust(ans2);
            }
            if(intcmp(ans1,ans2)>=1){
                intcpy(f[i][j],ans1);
            }
            else{
                intcpy(f[i][j],ans2);
            }
        }
    }
    for(int i=1;i<=m;++i){
        //f[i][i]+=(x[i]*cnt);
        int plust=x[i],cnt=m+1;
        while(plust){
            if(plust&1){
                f[i][i][cnt]+=1;
            }
            cnt++;plust>>=1;
        }
        adjust(f[i][i]);
    }
    int tmp[201]={0};
    intcpy(tmp,f[1][1]);
    for(int i=2;i<=m;++i){
        if(intcmp(tmp,f[i][i])==-1){
            intcpy(tmp,f[i][i]);
        }
    }
    //wtf?
    /*for(int i=tmp[0];i>=1;--i){
        tmp[i+1]=tmp[i];
    }
    tmp[1]=0;tmp[0]=tmp[0]+1;*/
    //
    memset(ansp,0,sizeof(ansp));
    intcpy(ansp,tmp);
}

void adjust(int a[]){
    for(int i=1;i<=201;++i){
        /*int cnt=i,tmp=a[i];a[i]=0;
        while(tmp){
            if(tmp&1) a[cnt]++;
            cnt++;tmp>>=1;
        }*/
        a[i+1]+=a[i]/2;
        a[i]%=2;
    }
    int len=200;
    while(a[len]==0&&len>1){
        len--;
    }
    a[0]=len;
}

void intcpy(int a[],int b[]){
    for(int i=0;i<=b[0];++i){
        a[i]=b[i];
    }
}

int intcmp(int a[],int b[]){
    if(a[0]>b[0]) return 1;
    if(a[0]<b[0]) return -1;
    for(int i=a[0];i>=1;--i){
        if(a[i]>b[i]) return 1;
        if(a[i]<b[i]) return -1;
    }
    return 0;
}

void intplus(int a[],int b[]){
    int len=1;
    while(len<=a[0]||len<=b[0]){
        a[len]+=b[len];
        len++;
    }
    len=200;
    while(a[len]==0&&len>1) len--;
    a[0]=len;
}

void print(int x[]){
    int ans[200]={0},plust[200]={0};
    plust[0]=1;plust[1]=1;
    for(int i=1;i<=x[0];++i){
        if(x[i]==1){
            //plus model:
            int len=1;
            while(len<=plust[0]||len<=ans[0]){
                ans[len]+=plust[len];
                ans[len+1]+=ans[len]/10;
                ans[len]%=10;
                len++;
            }
            if(ans[len]==0) len--;
            ans[0]=len;
        }
        //time model:
        int k=0;
        for(int i=1;i<=plust[0];++i){
            plust[i]*=2;
            plust[i]+=k;
            k=plust[i]/10;
            plust[i]%=10;
        }
        if(k!=0) plust[++plust[0]]=k;
    }
    if(ans[0]==0){
    	printf("0");
    }
    else{
   		for(int i=ans[0];i>=1;--i){
   		    	printf("%d",ans[i]);
    		}
    	printf("\n");
	}
}

猜你喜欢

转载自www.cnblogs.com/ticmis/p/13210911.html