LG11243
为了方便思考,以下分析满足条件 \(i<j\)。对于 \(i>j,a_i<a_j\) 的情况,则转化为 \(i<j,a_i>a_j\)(前后对调)。
先分析 \(i<j,a_i<a_j\) 的情况。显然,必须要满足 \(a_i \le a_{i + 1} \le a_{i + 2} \le \cdots \le a_j\) 时,才有可能产生贡献,否则一定可以构造反例。除此之外,为了保证 \(a_i < a_j\),必须至少存在一个 \(k \in [i,j)\) 使 \(a_k < a_{k+1}\),这样才能产生贡献。\(i<j,a_i>a_j\) 的情况同理。于是不难写出 \(O(n^2)\) 的做法:
#include <iostream>
#include <cstdio>
using namespace std;
int n,c[1000001],ans,flag;
string s;
int main()
{
int T;
cin >> T;
while( T -- )
{
cin >> n;
cin >> s;
ans = 0;
for( int i = 1 ; i < n ; i ++ )
{
if( s[i - 1] == '>' ) c[i] = 1;
if( s[i - 1] == '=' ) c[i] = 2;
if( s[i - 1] == '<' ) c[i] = 3;
}
for( int i = 1 ; i <= n ; i ++ )
{
flag = 0;
for( int j = i ; j < n ; j ++ )
{
if( c[j] == 1 ) break;
if( c[j] == 3 ) flag = 1;
if( flag ) ans ++;
}
flag = 0;
for( int j = i ; j < n ; j ++ )
{
if( c[j] == 3 ) break;
if( c[j] == 1 ) flag = 1;
if( flag ) ans ++;
}
}
cout << ans << '\n';
}
return 0;
}
考虑优化该算法。还是以 \(i<j,a_i<a_j\) 的情况为例,固定 \(i\) 后,第一个产生贡献的位置应该是第一个 \(k\) 使 \(a_{k-1} < a_k\),最后一个产生贡献的位置应该是第一个 \(l\) 使 \(a_l > a_{l+1}\)(之后的一定都不合法)。根据上文的分析,在 \([k,l]\) 上都能产生贡献。因此预处理每个位置后的第一个大于号和小于号的位置,再一遍计算贡献即可。
时间复杂度 \(O(n)\)。
#include <iostream>
#include <cstdio>
#define int long long
using namespace std;
int n,c[1000001],f1[1000001],f2[1000001],ans,flag1,flag2,pd1,pd2;
string s;
signed main()
{
int T;
cin >> T;
while( T -- )
{
cin >> n;
cin >> s;
ans = 0;
for( int i = 1 ; i < n ; i ++ )
{
if( s[i - 1] == '>' ) c[i] = 1;
if( s[i - 1] == '<' ) c[i] = 2;
if( s[i - 1] == '=' ) c[i] = 3;
f1[i] = f2[i] = 0;
}
f1[n] = f2[n] = 0;
for( int i = n - 1 ; i >= 1 ; i -- )
{
f1[i] = f1[i + 1];
f2[i] = f2[i + 1];
if( c[i] == 1 )
f1[i] = i;
if( c[i] == 2 )
f2[i] = i;
}
for( int i = 1 ; i < n ; i ++ )
{
if( f1[i] )
{
if( !f2[i] )
ans += n - f1[i];
else if( f2[i] > f1[i] )
ans += f2[i] - f1[i];
}
if( f2[i] )
{
if( !f1[i] )
ans += n - f2[i];
else if( f1[i] > f2[i] )
ans += f1[i] - f2[i];
}
}
cout << ans << '\n';
}
return 0;
}

浙公网安备 33010602011771号