BZOJ3770: 疯狂的限制

来源:互联网 发布:多台docker php-fpm 编辑:程序博客网 时间:2024/05/22 21:52

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<<endlusing 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);}
原创粉丝点击