CodeForces 1373 - C. Pluses and Minuses - 思维 / 计数问题(详解)

题目传送门:C. Pluses and Minuses

题目大意

给一个由'+'和'-'组成的操作序列,所求res初始为0;

对于一个变量cur(初始值为0),经过'+'字符,cur + 1,经过'-'字符,cur - 1,每经过一次操作res + 1,如果在执行序列的过程中cur<0则break;

使cur的初始值+1并重新执行操作序列(注意res不清零),直到在cur的初始值为某个值的情况下完整的执行完操作序列且不中断(也就是cur在执行过程中一直大于等于0),求最终res的值。(下面附上题目所给伪代码)

res = 0
for init = 0 to inf
    cur = init
    ok = true
    for i = 1 to |s|
        res = res + 1
        if s[i] == '+'
            cur = cur + 1
        else
            cur = cur - 1
        if cur < 0
            ok = false
            break
    if ok
        break

思路

其实就是个计数问题,当然也可以算是个思维题

很显然我们不会真的去执行,res每次只加1,那样在全为'-'的极限情况复杂度为O(n^2),我们只要知道每次在哪里break,那么通过下标我们就可以知道对于某个cur,res要加多少,这样复杂度就变为O(n)

那么我们可以正经地分析一下伪代码,在某次执行序列地第i个操作时cur < 0 break,紧接着cur初始值+1,那么这次cur在第i个操作一定不会小于0,只可能在i之后break,那么我们就只需要遍历一次操作序列;

最后一个问题就是我们如何知道下一次在哪break?

其实我们只需要一个minx来保存cur的下界限制,当cur < minx时break,然后使minx = cur(或者minx --,因为cur初始值每次只加1,每次操作只会加1或减1,下次break时的cur也只会比这次小1),相当于cur初始值 + 1(当然也可以把cur清零,因为在第i个操作break后cur初始值+1,然后再执行到操作i时cur会等于0,cur作用是让我们知道在哪break)

本题的关键就是发现break位置的单调性并且直接通过序列下标获取操作数而不用每次重复执行序列,我看了一些别人写的代码,也发现别人的不同思路:通过一次预处理得到每次break的位置和总的break次数,计算操作序列的下标为i的操作的执行次数(1\leqslant i \leqslant |s| ),但是代码量要多一些。(我的是计算每次break之前的执行次数 - 通过序列下标)

代码

#include 
using namespace std;
#define pb push_back
#define mp make_pair
#define fi first
#define se second
typedef long long ll;
typedef unsigned long long ull;
typedef pair PII;
typedef pair pll;
const int mod = 1e9 + 7;
const int N = 1e6 + 10;
const int INF = 0x3f3f3f3f;
ll qpow(ll base, ll n){ll ans = 1; while (n){if (n & 1) ans = ans * base % mod; base = base * base % mod; n >>= 1;} return ans;}
ll gcd(ll a, ll b){return b ? gcd(b, a % b) : a;}
char s[N];
int main()
{
	int t;
	cin >> t;
	while (t --){
		scanf("%s", s + 1);
		int n = strlen(s + 1);
		ll ans = 0, sum = 0, minx = 0;
		for (int i = 1; i <= n; ++ i){
			if (s[i] == '+') ++ sum;
			else -- sum;
			if (sum < minx) {
				minx = sum;
				ans += i;//本次break之前序列执行了i步
			}
		}
		ans += n;//最后一次不会break,序列全部执行
		cout << ans << '\n';
	}
	return 0;
}

 

你可能感兴趣的:(CodeForces 1373 - C. Pluses and Minuses - 思维 / 计数问题(详解))