BZOJ3770: 疯狂的限制
乱搞
题解:
枚举一个右端点r,设f[i]表示子区间[i,r]满足几个限制。
r每向右一动一位,枚举限制来更新f[].
复杂度:每个限制对每个点都只会+1一次-1一次,因此O(kn).
还有一些小细节,具体见代码。
Code:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#define D(x) cout<<#x<<" = "<<x<<" "
#define E cout<<endl
using namespace std;
const int N = 100005;
char str[N],tp[5];
int n,len,L,R,f[N];
vector<int> pos[30];
long long res,ans;
struct Lim{ int c,l,r; } d[505];
//在f加减的同时维护ans,即当前满足L、R限制的区间个数
void inc(int i){ f[i]++; if(f[i]==L)ans++; if(f[i]==R+1)ans--; }
void dec(int i){ f[i]--; if(f[i]==L-1)ans--; if(f[i]==R)ans++; }
int main(){
freopen("a.in","r",stdin);
scanf("%s",str); len=strlen(str);
scanf("%d%d%d",&n,&L,&R);
for(int i=1;i<=n;i++){ scanf("%s%d%d",tp,&d[i].l,&d[i].r); d[i].c=tp[0]-'a'; }
for(int i=0;i<26;i++)pos[i].push_back(-1);
for(int i=0;i<len;i++){
int j=str[i]-'a'; if(L==0)ans++;//f[i]现在是0,如果L==0则它满足要求
pos[j].push_back(i); int cnt=pos[j].size()-1;
for(int k=1;k<=n;k++) if(d[k].l==0)inc(i);//d[k].l==0的不适用与下面的规则,特殊处理
for(int k=1;k<=n;k++){
if(d[k].c!=j) continue;
if(cnt>=d[k].l && d[k].l!=0)//某个区间的f将会+1,照着代码自己画图看看
for(int p=pos[j][cnt-d[k].l]+1;p<=pos[j][cnt-d[k].l+1];p++)inc(p);
if(cnt>d[k].r)//某个区间的f将会-1,照着代码自己画图看看
for(int p=pos[j][cnt-d[k].r];p>pos[j][cnt-d[k].r-1];p--)dec(p);
}
res+=ans;
}
printf("%lld\n",res);
}