事情是这样的:
今天我在洛谷上刷题,遇到一个UASCO的题,虽然是橙题,但是还是很有滋味的
看了看大佬的思路发现太抽象了,评论区不是%%%就是orz,因此有了这篇题解
题解原文
这绝对是最短的题解了。。。(难理解别打我。)附上样例的输出以及中间结果来帮助理解:
c a b w ans
0 1 1 0
0 2 2 0
0 3 3 0
b 0 4 0 3
b 0 5 0 3
r 5 1 0 5
r 5 2 1 5
r 5 3 0 5
b 3 1 0 8
r 1 1 0 8
b 1 1 0 8
r 1 1 0 8
r 1 2 0 8
b 2 1 0 8
r 1 1 0 8
b 1 1 0 8
r 1 1 0 8
r 1 2 1 8
r 1 3 0 8
r 1 4 1 8
r 1 5 2 8
r 1 6 0 8
b 6 1 0 8
b 6 2 1 8
r 1 2 0 8
r 1 3 1 8
r 1 4 0 8
r 1 5 0 8
b 5 1 0 8
b 5 2 1 8
b 5 3 2 8
b 5 4 3 8
b 5 5 0 8
b 5 6 0 8
r 6 1 0 11
r 6 2 1 11
r 6 3 0 11
b 3 1 0 11
r 1 1 0 11
b 1 1 0 11
r 1 1 0 11
r 1 2 0 11
b 2 1 0 11
r 1 1 0 11
b 1 1 0 11
r 1 1 0 11
r 1 2 1 11
r 1 3 0 11
r 1 4 1 11
r 1 5 2 11
r 1 6 0 11
b 6 1 0 11
b 6 2 1 11
r 1 2 0 11
r 1 3 1 11
r 1 4 0 11
r 1 5 0 11
b 5 1 0 11
11 c:当前处理的字符
a:从i向左最长的长度
b:从i向右最长的长度
w:当前w个数
我们知道:当b重新计算时,其实a已经算好了。。就是b-w(当前的w已经算在b里面了)(正着反着不是一样的吗)
而b重新计算时,又应该加上前面w的个数
好像没什么了。。。更新答案应该在b算完的时候。。a在上一轮已经算过了。。
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
char s[700],c;
int a, b, w, ans;
int main(){int n;scanf("%d%s",&n,s);memcpy(s+n,s,n);//printf(" c a b w ans\n");for(int i = 0; i < n<<1; i++) {if(s[i] == 'w') b++,w++;elseif(s[i] == c ) b++,w=0;elseans=max(ans,a+b),a=b-w,b=w+1,w=0,c=s[i];//printf("%2c %2d %2d %2d %2d\n",c,a,b,w,ans);}ans=max(ans,a+b);printf("%d\n",min(ans,n));return 0;
}
首先给了我们一个字符串s,由于要求环形,我们要复制一份s
- 为什么?因为你把甜甜圈切开,你得再加一个被切开的甜甜圈才能确保他完整
接着看下数据范围\(1<=n<=350\),枚举法绰绰有余
我们枚举每一个空隙(注意枚举两遍,刚才复制了个s)
我们设w为白色节点连续出现的次数,c是现在枚举的是r/b,a是往左有多少,b是往右
如果是‘w’,更新b,更新w
如果是c,更新b,清零w
否则:
记录ans(ans是什么?a+b嘛!)
直接找到a(a=b-w)
- 为什么可以这样?由于我们说过s被复制了一份,那就说明a跟b连接着,只要减去w(因为如果w变成r就没法再变成b,这是一坑)
把b设为w+1(1是现在枚举到的这个字符)
重置w
记录现在字符为c
最后输出时记得再统计一遍ans
如果ans比n大输出n(由于我们复制了一遍不排除这种可能性)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
string s;
int ans,n,a,b,w,c;
int main()
{cin>>n>>s;s+=s;for(auto i:s){if(i=='w')b++,w++;else if(i==c)b++,w=0;else ans=max(ans,a+b),a=b-w,b=w+1,w=0,c=i;}ans=max(ans,a+b);cout<<min(ans,n);return 0;
}