题意:给N个台阶 每个台阶有一个字母 U代表上 D代表下 每个台阶走过一次就会转换,U换成D,D换成U。输出从第N个台阶走出去的步数。以样例中的3为例,就是UUD到UUU到UDU到UDD此时已经走出去了。
题解:我们可以写写画画,然后找到规律,对于当前位置,如果左边的U小于右边包括本身的D的个数,那么最后一定从左边出去,反之从右边出去。至于其他的步数,其实就是(左边的U到当前位置的距离 + 右边的D到当前位置的距离)* 2,然后左边U的个数和右边D的个数取MIN(左边U的个数,右边D的个数),这里面两个都包括自己。
举个例子 对于6 ,个数就是MIN(2,1) = 1, 然后就是左边1个U的距离1 * 2 + 右边一个D的距离1 * 2 = 4, 在加上从右边出去的距离(4 - 2), 答案就是6;
代码:
#include <bits/stdc++.h>
#define mem(a, b) memset(a, b, sizeof(a))
using namespace std;
int n, num[1000005];
__int64 ans[1000005], sumu[1000005], sumd[1000005];
char ch[1000005];
int main()
{
mem(ans, 0);
scanf("%d", &n);
scanf("%s", ch + 1);
sumu[0] = 0;
for(int i = 1;i <= n;i++)
{
if(ch[i] == 'U')
sumu[i] = sumu[i - 1] + 1;
else
sumu[i] = sumu[i - 1];
}
sumd[n + 1] = 0;
for(int i = n;i >= 1;i--)
{
if(ch[i] == 'D')
sumd[i] = sumd[i + 1] + 1;
else
sumd[i] = sumd[i + 1];
}
__int64 w = 0, l = 0, r = 0;
for(int i = 1;i <= n;i++)
{
if(r > l)
w += (r - l);
__int64 ll = min(sumu[i], sumd[i]);
if(r - l > ll)
{
while(r - l > ll)
{
__int64 pos = num[l + 1];
w -= (__int64)(i - pos);
l++;
}
}
ans[i] += 2 * w;
if(sumu[i - 1] < sumd[i])
ans[i] += (__int64)i;
if(ch[i] == 'U')
num[++r] = i;
}
w = 0, l = 0, r = 0;
for(int i = n;i >= 1;i--)
{
if(r > l)
w += (r - l);
__int64 ll = min(sumu[i], sumd[i]);
if(r - l > ll)
{
while(r - l > ll)
{
int pos = num[l + 1];
w -= (__int64)(pos - i);
l++;
}
}
ans[i] += 2 * w;
if(sumu[i - 1] >= sumd[i])
ans[i] += (__int64)n - (__int64)i + 1;
if(ch[i] == 'D')
num[++r] = i;
}
for(int i = 1;i <= n;i++)
printf("%I64d ", ans[i]);
printf("\n");
return 0;
}