RowGame TopCoder - 10664

传送门

分析

首先不难想到O(k)做法,即dpi表示进行了几次,但复杂度明显爆炸,所以思考更优做法。我们发现数字个数很小,仅为可怜的50,所以从这里找突破口。我们发现每次可以在一个固定区域内进行刷分活动,当分数可以安全渡过中间的负数时可以选择渡过负数到另一个刷分区刷分,也可以留在本来的区域继续刷分,得到这些之后我们便可以考虑如何求出刷分区了,我们不难想出以点i为结尾的刷分区肯定是i的最大后缀和,得到以上结论后我们就可以dp了,当然这个题也可以建图跑最短路,代码挺容易理解了,具体实现看代码吧。

代码

dp

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define sp cout<<"---------------------------------------------------"<<endl;
#define li long long
li num[1100],vl[1100],pre[1100],a[1100];
class RowGame{
      public:
          li score(vector<int>board,int k){
            int i,j,n=board.size();
            pre[0]=board[0];
            for(i=1;i<n;i++)
              pre[i]=(li)board[i]+pre[i-1];
            for(i=0;i<n;i++)
              if(pre[i]>=0){
                num[i]=k-1;
                vl[i]=pre[i];
              }
            a[0]=board[0];
            for(i=1;i<n;i++){
                a[i]=board[i];
                if(a[i-1]>0)
                  a[i]+=a[i-1];
            }
            li ans=0;
            for(i=0;i<n;i++)
              if(num[i]&&a[i]>0){
                ans=max(ans,vl[i]+num[i]*a[i]);
                li v=a[i]*2;
                for(j=i+1;j<n;j++){
                    li x=num[i]-2,y=vl[i]+v+pre[j]-pre[i];
                    if(y<0){
                      li t=(-y-1)/v+1;
                  x-=t*2;
                  y+=t*v;
                }
                if(x>num[j]||(x==num[j]&&y>vl[j])){
                  num[j]=x;
                  vl[j]=y;
                }
              }
            }
          return ans;
        }
};

建图+最短路

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define sp cout<<"---------------------------------------------------"<<endl;
#define li long long
int n,n2;
li g[1100][1100],a[1100],step[1100],vl[1100];
const li inf=1e16+7;
class RowGame{
      public:
          li score(vector<int>board,int k){
            int i,j,n=board.size(),n2=n+n;
          for(i=0;i<n2;i++)
            for(j=0;j<n2;j++)
              g[i][j]=-inf;
          for(i=0;i<n;i++){
            li s=0;
            for(j=i;j<n;j++){
              s+=board[j];
              g[i][j+n]=g[j+n][i]=s;
            }
          }
          for(i=0;i<n2;i++){
              a[i]=0;
              for(j=0;j<n2;j++)
                a[i]=max(a[i],g[i][j]+g[j][i]);
          }
          for(i=0;i<n2;i++){
            step[i]=inf;
            vl[i]=-inf;
          }
          step[0]=vl[0]=0;
          for(int p=0;p<n2;p++){
              for(i=0;i<n2;i++)
                if(step[i]!=inf)
                  for(j=0;j<n2;j++)
                    if(g[i][j]!=-inf){
                        li s=step[i],v=vl[i];
                        if(v+g[i][j]<0){
                          if(a[i]<=0)continue;
                          li ss=(-(v+g[i][j])-1)/a[i]+1;
                          s+=ss*2;
                          v+=ss*a[i];
                      }
                      v+=g[i][j];
                      s++;
                      if(s<step[j]||(s==step[j]&&v>vl[j])){
                        step[j]=s;
                        vl[j]=v;
                      }
                    }
          }
          li res=0;
          for(i=0;i<n2;i++)
            if(step[i]<=k){
              res=max(res,vl[i]);
              res=max(res,vl[i]+(k-step[i])/2*a[i]);
              if(step[i]!=k)
                for(j=0;j<n2;j++)
                  if(g[i][j]!=-inf)
                    res=max(res,vl[i]+(k-step[i]-1)/2*a[i]+g[i][j]);
            }
          return res;
        }
};
posted @ 2018-07-13 13:49  水题收割者  阅读(396)  评论(0编辑  收藏  举报