zoukankan      html  css  js  c++  java
  • 【NOIP2007】矩阵取数

    因为傻逼写错高精度搞了一下午浪费好多时间,好想哭qaq

    原题:

     帅帅经常更同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij据为非负整数。游戏规则如下:
      1. 每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有的元素;
      2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
      3. 每次取数都有一个得分值,为每行取数的得分之和;每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号);
      4. 游戏结束总得分为m次取数得分之和。

      帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

    1<=n, m<=80,0<=a[i][j]<=1000

    首先每一行怎么取互不影响,就可以分开来搞,最后加到一起,下面说的f,a都是某一行里的

    然后每一行中区间DP,f[i][j]表示i到j这个区间最大值多少,f[i][j]=max(f[i+1][j]+a[i],f[i][j-1]+a[j])*2

    在求f[i][j]的时候直接在后面*2,这样子就不用计算2^i的高精度运算

    高精度傻逼了一下午,能力会随着时间的推移降低

    记录傻逼的高精度错误:
    //for(int i=1;i<=x[0];i++)  x[i]=f[_left][_right][i]+z;高精度+单精度不是这么写的qaq

    正确做法:x[1]+=z

    while(x[x[0]+1]){  x[0]++;  x[x[0]+1]+=x[x[0]]/ss,x[x[0]]%=ss;}//如果没有每次都清空的话,会因为上一次遗留下来的数继续往后推

    //for(int i=1;i<=nleft[0];i++)if(nleft[i]!=nright[i])  return nleft[i]>nright[i];高精度比较应该先比高位qaq

    代码:

     1 //因为高精度傻逼了搞了一下午,好想哭qaq
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<cstring>
     6 using namespace std;
     7 const int ss=10000;
     8 int m,n,a[110][110];
     9 int ans[11000];
    10 int f[90][90][1100];
    11 int nleft[1100],nright[1100];
    12 void getn(int *x,int _left,int _right,int z){
    13     x[0]=f[_left][_right][0];
    14     //for(int i=1;i<=x[0];i++)  x[i]=f[_left][_right][i]+z;傻逼了qaq
    15     for(int i=1;i<=x[0];i++)  x[i]=f[_left][_right][i];
    16     x[1]+=z;
    17     for(int i=1;i<=x[0];i++)  x[i+1]+=x[i]/ss,x[i]%=ss;
    18     while(x[x[0]+1]){  x[0]++;  x[x[0]+1]+=x[x[0]]/ss,x[x[0]]%=ss;}//注意这里,如果没有每次都清空的话,会因为上一次遗留下来的数继续往后推
    19 }
    20 bool getmax(){
    21     if(nleft[0]>nright[0])  return true;
    22     if(nleft[0]<nright[0])  return false;
    23     //for(int i=1;i<=nleft[0];i++)if(nleft[i]!=nright[i])  return nleft[i]>nright[i];第二次傻逼qaq
    24     for(int i=nleft[0];i>=1;i--)if(nleft[i]!=nright[i])  return nleft[i]>nright[i];
    25     return true;
    26 }
    27 void fan(int *x){
    28     for(int i=1;i<=x[0];i++)  x[i]<<=1;
    29     for(int i=1;i<=x[0];i++)  x[i+1]+=x[i]/ss,x[i]%=ss;
    30     while(x[x[0]+1]){  x[0]++;  x[x[0]+1]+=x[x[0]]/ss,x[x[0]]%=ss;}
    31 }
    32 void jia(int *x,int *y){
    33     x[0]=max(x[0],y[0]);
    34     for(int i=1;i<=x[0];i++)  x[i]+=y[i];
    35     for(int i=1;i<=x[0];i++)  x[i+1]+=x[i]/ss,x[i]%=ss;
    36     while(x[x[0]+1]){  x[0]++;  x[x[0]+1]+=x[x[0]]/ss,x[x[0]]%=ss;}
    37 }
    38 void copy(int *x,int *y){  y[0]=x[0];  for(int i=1;i<=x[0];i++)  y[i]=x[i];}
    39 int main(){//freopen("ddd.in","r",stdin);
    40     //freopen("ddd.out","w",stdout);
    41     cin>>m>>n;
    42     for(int i=1;i<=m;i++)  for(int j=1;j<=n;j++)  scanf("%d",&a[i][j]);
    43     for(int k=1;k<=m;k++){
    44         memset(f,0,sizeof(f));
    45         for(int i=1;i<=n;i++)  f[i][i][f[i][i][0]=1]=a[k][i]*2;//因为输入数据保证a[i][j]<=1000所以直接塞进去就行了
    46         for(int l=2;l<=n;l++)
    47             for(int i=1,j=i+l-1;j<=n;i++,j++){
    48                 memset(nleft,0,sizeof(nleft)),memset(nright,0,sizeof(nright));
    49                 getn(nleft,i+1,j,a[k][i]),getn(nright,i,j-1,a[k][j]);
    50                 //cout<<nleft[0]<<endl;
    51                 copy((getmax() ? nleft : nright),f[i][j]);
    52                 fan(f[i][j]);
    53                 /*cout<<f[i][j][f[i][j][0]];
    54                 for(int t=f[i][j][0]-1;t>=1;t--)  printf("%04d",f[i][j][t]);
    55                 cout<<endl;*/
    56             }
    57         jia(ans,f[1][n]);
    58     }
    59     cout<<ans[ans[0]];
    60     for(int i=ans[0]-1;i>=1;i--)  printf("%04d",ans[i]);
    61     cout<<endl;
    62     return 0;
    63 }
    View Code
  • 相关阅读:
    !!!最常用正则表达式语法
    RunMessageScript from spy
    已知进程、线程、窗体三者中某一个的句柄,需要查找另外两者的句柄。
    如何抓取一个当前运行软件所使用的内存
    谢谢你的伤害
    游摸底河有感
    九月无诗
    游石人公园有感
    影响35岁前成功的好习惯与坏习惯
    创业经验十二谈,愿有志者共勉(转)
  • 原文地址:https://www.cnblogs.com/JSL2018/p/5939637.html
Copyright © 2011-2022 走看看