題意:共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;
}