B.Namomo子串(模擬&DP)
思路:簡單模擬&。
顯然我們只需每次找到類型的串,然後枚舉循環次數。
假設從長度爲9開始(前兩個不計算)的個數個,顯然開頭的貢獻數爲個(分別是長度爲)。
接下來不以開頭的子串顯然有個。
因爲長度爲的有個,的有個,長度爲有一個。
綜上
實現的話可以順序模擬,或者後再倒着計算。
注意有一個點是:
,這樣的串都是。所以每次遍歷完一個串後,下標應該置爲最後一個的,而不能變成的。
:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
char a[N];
char c[5]={'a','e','i','o','u'};
bool vis[N];
ll dp[N][2];
int main(){
scanf("%s",a+1);
int n=strlen(a+1);
for(int i=1;i<=n;i++){
int f=0;
for(int j=0;j<5;j++){
if(c[j]==a[i]){
f=1;
vis[i]=1;
break;
}
}
if(!f){
if(i>2&&a[i-2]==a[i]) dp[i][0]=max(dp[i-2][0]+1,1LL);
else dp[i][0]=1;
}
else {
if(i>2&&a[i-2]==a[i]) dp[i][1]=max(dp[i-2][1]+1,1LL);
else dp[i][1]=1;
}
}
ll ans=0;
for(int i=n;i>=6;i--){
if(vis[i]&&!vis[i-1]){
if(dp[i][1]<2||dp[i-1][0]<2) continue;
ll x=min(dp[i][1],dp[i-1][0]);
int len=x*2;
int st=i-1-len;
int f=0;
if(st<1) st+=2,f=1;
if(!f&&!vis[st]&&vis[st+1]){
ans+=(x-1)+(x-2)*(x-1)/2;
}
else ans+=(x-2)*(x-1)/2;
i=st+2;
}
}
printf("%lld\n",ans);
return 0;
}
順序模擬:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e5+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
char a[N];
char c[5]={'a','e','i','o','u'};
bool check(int i){
for(int j=0;j<5;j++) if(c[j]==a[i]) return 1;
return 0;
}
bool namo(int i){
if(!check(i)&&check(i+1)&&check(i+3)&&!check(i+2)&&a[i+2]==a[i+4]&&a[i+3]==a[i+5]) return 1;
return 0;
}
int main(){
scanf("%s",a+1);
int n=strlen(a+1);
ll ans=0;
for(int i=1;i+5<=n;i++){
if(namo(i)){
int j=i+6,k=j+1;
while(k<=n&&a[j]==a[i+2]&&a[k]==a[i+3]) j+=2,k+=2;
int len=k-2-i+1;
ll cnt=(len-6)/2;
ans+=cnt+(cnt+1)*cnt/2+1;
i=j-2-1;
}
}
printf("%lld\n",ans);
return 0;
}