[ABC 098] C-Attention

C - Attention


Time limit : 2sec / Memory limit : 1024MB

Score : 300 points

Problem Statement

There are N people standing in a row from west to east. Each person is facing east or west. The directions of the people is given as a string S of length N. The i-th person from the west is facing east if Si= E, and west if Si= W.

You will appoint one of the N people as the leader, then command the rest of them to face in the direction of the leader. Here, we do not care which direction the leader is facing.

The people in the row hate to change their directions, so you would like to select the leader so that the number of people who have to change their directions is minimized. Find the minimum number of people who have to change their directions.

Constraints

  • 2≤N≤3×105
  • |S|=N
  • Si is E or W.

[题目解释]

  给你个长度为N的字符串S,从西到东连续排列N(2≤N≤3×105)个人,Si='E'表示第i个人朝向东,Si='W'则第i个人朝向西,我们在N个人中寻找一位成为领导者,其他人均需要领导者(若背向领导者需要转向),求最少转向的人的数目

[题目解析]

  由于我们并不知道那个人成为领导者时需要转向的人最少,我们需要枚举每一个人成为领导者时转向的人的数目.可是若我们每次枚举时都向前统计一遍朝向西的人,向后统计朝向东的人,这样计算的时间复杂度是O(n2)的可2≤N≤3×105这样的时间复杂度显然是不能通过的.我们发现如果领导者前一位是朝向东的那么并不改变领导者前面需要改变方向的人数,若朝向西的则需改变方向的人数是这个人之前朝向西的人数+1,这样我们就可以发现我们从左到右枚举领导人,其左边需要改变方向的人是只增不减的,于是我们可以对朝向西的人做一次前缀和(当然朝向东的也行,不过下面的推导式需要修改)记入进num数组中,当第i位成为领导者时,其前面需要转向的人就是i-num[i-1]个人,其后面需要转向的人就是n-i(一共n-i个人)-(tot-num[i])(tot表示朝向西的人总数,tot-num[i]表示i+1~n朝向西的人)我们每次枚举领导者把答案更新在ans里即可,时间复杂度O(n)

[代码]

 

/*
    Name: Attention 
    Author: FZSZ-LinHua
    Date: 2018 06 06
    Exec time: 13ms
    Memory usage: 1796KB
    Score: 300 
    Algorithm: Brute-force 
*/
# include "cstdio"
# include "iostream" 
 
using namespace std;

const int maxm=300000+10; 

int num[maxm],  //num[i]表示第i位上朝向西的人数('W') 
    tot,    //朝向西的总人数
    ans;    //当前改变方向的最少人数
     
int main(){
    int n; //N为序列长度 
    string s;  //一个长度为N的字符串,其中只包含'E','W' 
    scanf("%d",&n); 
    cin>>s;
    if(s[0]=='W'){  //先处理第一位 
        num[0]++; 
    } 
    for(int i=1;i<n;i++){
        num[i]=num[i-1];
        if (s[i]=='W'){
            num[i]++;
        }
    }
    tot=num[n-1];  //一共有num[n-1]位朝向西 
    int ans=n-tot; //ans初始化为第1位同学成为领导者需要改变方向的人数 
    if(s[0]=='E'){ //如果第1位同学朝向东('E')第i位同学不必转向 
        ans++; 
    } 
    for (int i=1;i<n;i++) {    //枚举领导者 
        int left=num[i-1];    //i成为领导者时1~i-1向西的同学需要转向 
        int right=n-(i+1)-(tot-num[i]); //i成为领导者时i+1~n向东的同学需要转向
        //其中一共n-i位同学,向西的同学有tot-num[i]位
        //由于string下标从0开始这里计算人数时i成为领导者时包括i在内一共i+1个人(只影响n-i时的数值,并不影响tot-num[i]的数值) 
        ans=min(ans,left+right);
    }
    printf("%d",ans);
    return 0;
}

 

 

 

posted @ 2018-06-07 00:14  FJ-Frank  阅读(315)  评论(0)    收藏  举报