(第11回ブルーブリッジカップ州大会)テスト問題H:部分文字列スコアの合計(思考)(例は正しくありません)

トピックリンク:注目のプロジェクトコース_IT人気のコース_ブルーブリッジクラウドコース-ブルーブリッジクラウドコース

分析:この質問はまだ良い質問だと思うので、来て記録してください:

まず、nのデータ範囲を見ると、この問題はo(n)またはo(nlogn)の複雑さでのみ通過できることがわかります。もちろん、o(n ^ 2)も部分的なポイントを取得できます。以下に正しい解決策を示してください。

Sの各部分文字列をトラバースしてそのf値を見つけることは不可能ですが、最終的な答えに対するSの各文字の寄与を見つけ、最後に各文字の寄与を合計することができます。例としてababcを取り上げ、分析してみましょう。 3番目の文字の寄与が最初です。これが彼を含む各サブストリングに1を寄与していると仮定すると、彼はSシーケンスの左から3番目であり、から3番目でもあるため、彼の寄与は3 * 3=9です。右。Sの最初の3つの位置からlとして番号を選択し、次にSの最後の3つの位置からrとして番号を選択すると、[l、r]シーケンスにThis aが含まれますが、すぐに計算が繰り返されるため、このように問題を考えるのは誤りです。たとえば、abaもSの部分文字列ですが、この部分文字列には2つのaがあります。寄与はどちらに属しますか?したがって、明らかに今のように計算することはできません。現在の文字の貢献間隔の間隔lは、現在の文字が最後に表示された位置の最初の位置から右側までの間隔に含まれているということです。現在の文字、および現在の文字の寄与は次のとおりです。間隔のrには、現在の文字の次の出現の左側の最初の位置から現在の文字の位置までの間隔が含まれます。selectは各文字を1回しか含めることができませんが、この方法でいくつかのケースを見逃します。abaの場合、私たちの文字がまだ貢献していることを見つけるのは難しくありませんが、定義したのと同じ文字を含むサブストリングに移動することはできません。 、したがって、そのように寄与を定義すると、リークが発生します。、各サブストリングを確実に考慮するために、文字の寄与を次のように定義できます。現在の文字の寄与の間隔lには、現在の文字への間隔が含まれます。現在の文字が最後に表示された位置の1つ右の文字、および現在の文字の寄与間隔のrは、現在の文字の位置からS文字列の右端までの間隔に含まれます。選択したサブストリングに繰り返し文字が現れるたびに、文字列の寄与が最初の文字としてカウントされること。文字の出現の寄与、各文字の寄与を繰り返しなしで計算できるようにします。特殊なケースとして、文字の左側に同じ文字がない場合は、左側の境界に従って処理できます。

コードは次のとおりです。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
const int N=30;
vector<int>p[N];
int main()
{
	string s;
	cin>>s;
	long long len=s.size();
	s=" "+s;//让下标从1开始 
	for(int i=1;i<=len;i++)
		p[s[i]-'a'+1].push_back(i);
	long long ans=0;
	for(int i=1;i<=len;i++)
	{
		int t=s[i]-'a'+1;
		int last;
		int id=lower_bound(p[t].begin(),p[t].end(),i)-p[t].begin();//求出第i个字母是第几次出现 
		if(id) last=p[t][id-1]+1;
		else last=1;
		ans+=(i-last+1)*(len-last+1);
	}
	cout<<ans;
	return 0;
}

おすすめ

転載: blog.csdn.net/AC__dream/article/details/123972726