题意:共1<=n<=5e5个照片,从第一个照片开始显示,看一张照片需要1 second,翻到左边或者右边的照片需要1<=a<=1000 second,如果这张照片是'w’状态即水平的时候需要花费1<=b<=1000 second旋转过来再看,翻到已经看过的照片不需要翻转也不需要重复看,不允许跳过没有看过的照片,问1<=T<=1e9 秒最多可以看多少照片;
链接:http://codeforces.com/contest/651/problem/D
一开始没有理解题意,都怪自己英语太渣渣了
思路:共500000张照片,允许复杂度为O(n*logn);可以想到想某一方向走到水平照片且翻转照片代价较大的时候,可能存在反方向到第n-1,第n-2....但是不可能一张照片经过第三次,这样就不是最优解了。所以可能是先向左走在折返向右,或者先向右走再折返向左;
先向左枚举折返点,然后向右二分寻找最左边的点;再向右枚举折返点,然后二分寻找最左边的点;
注意二分寻找的边界,不能与所枚举的点所代表的数列有重合;
时间复杂度为O(n*logn)
我的代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <queue>
#include <algorithm>
#define N 500050
using namespace std;
int n,a,b,t;
char ma[N];
int sum[N];
int dsum[N];
int ans,maxx;
int main()
{
int i,j;
while(~scanf("%d%d%d%d",&n,&a,&b,&t)){
scanf("%s",ma);
memset(sum,0,sizeof(sum));
if(ma[0]=='w')
sum[0]=b+1;
else sum[0]=1;
for(i=1;i<n;i++){
sum[i]=sum[i-1]+a+1;
if(ma[i]=='w')
sum[i]+=b;
}
if(ma[n-1]=='w')
dsum[n-1]=a+b+1;
else dsum[n-1]=a+1;
for(i=n-2;i>=1;i--){
dsum[i]=dsum[i+1]+a+1;
if(ma[i]=='w')
dsum[i]+=b;
}
if(sum[n-1]<=t){
printf("%d\n",n);
continue;
}
ans=0;
for(i=0;i<n&&sum[i]<=t;i++){
if(sum[i]+a*i<t){
int left=i+1,right=n-1;
int ans2=-1;
while(left<=right){
int mid=(left+right)>>1;
if(sum[i]+a*i+dsum[mid]<=t){
ans2=mid;
right=mid-1;
}
else
left=mid+1;
}
if(ans2!=-1){
ans=max(i+1+n-ans2,ans);
}
}
else{
ans=max(ans,i+1);
}
}
for(i=n-1;i>=1&&dsum[i]+sum[0]<=t;i--){
if(dsum[i]+sum[0]+a*(n-i)<t){
int left=1,right=i-1;
int ans2=-1;
while(left<=right){
int mid=(left+right)>>1;
if(dsum[i]+sum[mid]+a*(n-i)<=t){
ans2=mid;
left=mid+1;
}
else
right=mid-1;
}
if(ans2!=-1){
ans=max(n-i+ans2+1,ans);
}
}
else{
ans=max(ans,n-i+1);
}
}
printf("%d\n",ans);
}
return 0;
}