2018ICPC青岛网络赛-Traveling on the Axis 思路题

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5809

题意:n个红绿灯,每个等左右有两个点,标号0~n,t(p,q)表示从点p走到点q花费的时间,每路过一个灯花费1s,如果是红灯不能通行,绿灯可以,每过1s红灯变为绿灯,绿灯变红灯,1表示绿灯,0表示红灯。问t(0,n)+..t(0,1)+t(1,n)+..+t(1,2)+......+t(n-1,n)。

思路:如果这个灯前面的灯不同,那么通过这个灯不需要等待,例如:01,通过第一个灯用了2s,这是第二个灯是绿灯,10也是如此。

   基于以上结论,每个灯花费的时间就分为三个部分:1.经过灯必定花费的1s;2.因为和前面的灯不同而需要等待的1s;3.初始状态为0,作为第一个路灯时,必须等待的1s。

     第一种情况很好求,第二种和第三种就是统计这个灯在所有t(p,q)中出现的次数。

代码:

#include <iostream>
#include <algorithm>
#include <string>
#include <string.h>
#define maxlen_s 100009
#define ll long long

using namespace std;

int sum_sum[maxlen_s]; //前n项和的前n项和
int wait_qian[maxlen_s]; //第二种情况
int wait_self[maxlen_s]; //第三种情况
int arr[maxlen_s];//路灯的初始状态
string ss;

void setsum_sum() {
    sum_sum[1] = 1;
    for (int i = 2; i <= 100002; i++) {
        sum_sum[i] = ((i*(i + 1)) >> 1) + sum_sum[i - 1];
    }
}
void setwait(int len) {
    arr[0] = 0;
    for (int i = 1; i <= len; i++) {
        if (arr[i] == 0) wait_self[i] = 1;
        if (arr[i - 1] == arr[i]) wait_qian[i] = 1;
    }
    wait_qian[1] = 0;
}

int main() {
    setsum_sum();

    int t;
    scanf("%d", &t);
    getchar();

    while (t--)
    {
        cin >> ss;

        for (int i = 0; i<ss.length(); i++) {
            if (ss[i] == '1') arr[i + 1] = 1;
            else arr[i + 1] = 0;
        }
        setwait(ss.length());

        ll ans = sum_sum[ss.length()];
        for (int i = 1; i <= ss.length(); i++) {
            if (wait_qian[i]) {  //此处i>=2
                ans += (ss.length() - i + 1) + (i - 2);
            }
            if (wait_self[i]) {
                ans += ss.length() - i + 1;
            }
        }
        printf("%lld\n", ans);

        memset(wait_qian, 0, sizeof wait_qian);
        memset(wait_self, 0, sizeof wait_self);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/the-way-of-cas/p/9664867.html
今日推荐