Codeforces Problem - 1016C
[http://codeforces.com/problemset/problem/1016/C]
题意:一个N,2×N 个数,从[1, 1]点开始将所有点全部遍历完,输出遍历的最大值。遍历的规则是(遍历的顺序-1)×当前的那个数。
题解:使用前缀和解决这个问题,思路是将N分成两块,左边是一上一下的折叠状,右边的是直走再转回来那种。求前缀和优化思路就好。 题目非常灵活有很多可以优化的地方。
#include <cstdio>
using namespace std;
typedef long long ll;
const int MAXN = 3e5+5;
ll dp[MAXN][2]={0};
ll step[MAXN][2]={0};
ll dis[MAXN*2][2]={0};
ll vis[MAXN*2][2]={0};
ll num[MAXN][2];
ll max(ll a,ll b){
return a>b?a:b;
}
ll odd(int x,int N){
ll res=dp[x][0],cnt=step[x][0]+1;
res+=dis[N*2-1-x][0]-dis[x][0]+(vis[2*N-1-x][0]-vis[x][0])*(cnt-x-1);
return res;
}
ll even(int x,int N){
ll res=dp[x][1],cnt=step[x][1]+1;
res+=dis[N*2-1-x][1]-dis[x][1]+(vis[2*N-1-x][1]-vis[x][1])*(cnt-x-1);
return res;
}
int main(){
int N;
scanf("%d",&N);
for(int i=0;i<2;i++){
for(int j=0;j<N;j++){
scanf("%d",&num[j][i]);
dp[j][i]=num[j][i];
}
}
ll cnt=0;
int x=0,y=0;
dp[0][0]=0;
while(cnt<2*N){
int dx=x,dy=y;
if(y==0){
if(x%2==0)y=1;
else x++;
}
else{
if(x%2==0)x++;
else y=0;
}
dp[x][y]=dp[x][y]*(cnt+1)+dp[dx][dy];
step[x][y]=cnt+1;
// printf("%d %d %d
",x,y,dp[x][y]);
cnt++;
}
for(int i=0;i<N;i++){
vis[i][0]=num[i][0];
vis[i][1]=num[i][1];
}
for(int i=0;i<N;i++){
vis[i+N][0]=num[N-i-1][1];
vis[i+N][1]=num[N-i-1][0];
}
for(int i=0;i<2*N;i++){
dis[i][0]=vis[i][0]*i;
dis[i][1]=vis[i][1]*i;
if(i){
dis[i][0]+=dis[i-1][0];
dis[i][1]+=dis[i-1][1];
vis[i][0]+=vis[i-1][0];
vis[i][1]+=vis[i-1][1];
}
}
// for(int i=0;i<2;i++){
// for(int j=0;j<2*N;j++)
// printf("%d ",vis[j][i]);
// printf("
");
// }
// for(int i=0;i<2;i++){
// for(int j=0;j<2*N;j++)
// printf("%d ",dis[j][i]);
// printf("
");
// }
// for(int i=0;i<2;i++){
// for(int j=0;j<N;j++){
// printf("%lld ",dp[j][i]);
// }
// printf("
");
// }
// for(int i=0;i<2;i++){
// for(int j=0;j<N;j++)
// printf("%lld ",step[j][i]);
// printf("
");
// }
ll maxx=dp[N-1][N%2];
for(int i=0;i<N;i++){
if(i%2==0)maxx=max(maxx,odd(i,N));
if(i%2==1)maxx=max(maxx,even(i,N));
}
printf("%lld
",maxx);
return 0;
}