BZOJ3770: 疯狂的限制

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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值