疯狂的限制(疯狂的暴力-挪动合法序列区间)

Problem 3 疯狂的限制(lunatic.cpp/c/pas)

【题目描述】

[题目简述]

给定k个限制条件,其中第i个条件用c[i],l[i],r[i]表示:

字符c[i]在字符串中的出现次数大等于l[i],小等于r[i]。

若一个字符串满足的限制条件的个数大等于L,小等于R,则称该串为StenisString

给定一小写字母串s,求s有多少个子串是SteinsString。

 

OkabeRintarou觉得一般的字符串问题弱爆了,所以他自己编了道题目:

内嵌[题目简述]

结果这题被桶子秒了。

“正因无意义才有其存在意义。”

【输入格式】

第一行一个非空的小写字母串s

第二行三个整数k,L,R。

以下k行,每行1个字符和2个整数表示c[i],l[i],r[i]

【输出格式】

一个整数,表示答案

【样例输入】

elpsycongroo

3 1 2

o 2 4

a 1 2

y 1 3

【样例输出】

48

【数据范围】

对于10%的数据 k=1,|s|<=200

对于30%的数据 k<=100,|s|<=200

对于另外30%的数据 L=R=K

对于100%的数据 0<=L<=R<=k<=500,0<=l[i]<=r[i]<=|s|,|s|<=10^5


这题解法是

Case 1:枚举区间右端点

Case 2:a[x]表示以x为左端点满足的条件数

Case 3:暴力确定所有条件,可以发现每个条件对区间的影响是1段+1,1段-1

Case 4:到这里就不会了(弱TNT),从上午2点弄到现在……

看来Dp要加强了……(连暴力都不会的X1)


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define Rep(i,n) for(int i=0;i<n;i++)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define MAXN (100000+10)
#define MAXK (500+10)
#define MAXDy (26)
struct seg
{
    int l,r;
    seg():l(0),r(0){}
}line;
int n,m,k,L,R,l[MAXK],r[MAXK],a[MAXN]={0};
char s[MAXN],c[MAXK];
int su[MAXDy][MAXN]={0},p[MAXDy]={0},tot=0;
long long ans=0;
bool check(int i,int j)
{
    int t=0;
//  if (s[i]==c[j]) t++;//cout<<t<<' '<<s[i]<<' '<<c[j]<<' ';
    if (l[j]<=t&&t<=r[j]) return 1;return 0;
}
void add(int l,int r,int c)
{
//    cout<<':'<<l<<' '<<r<<' '<<c<<endl;
    Fork(i,l,r)
    {
        if (L<=a[i]&&a[i]<=R) tot--;
        a[i]+=c;
        if (L<=a[i]&&a[i]<=R) tot++;
    }
}
int main()
{
    scanf("%s\n",s+1);s[0]=' ';n=strlen(s)-1;
    scanf("%d%d%d\n",&m,&L,&R);
    For(i,m) scanf("%c%d%d\n",&c[i],&l[i],&r[i]);
    For(i,n) su[s[i]-'a'][++su[s[i]-'a'][n+1]]=i;
    For(i,n)
    {
        p[s[i]-(int)'a']++;//cout<<tot<<' ';
        /* un L 原来满足要求 */
        For(j,m) if (!l[j]) a[i]++;
        if (L<=a[i]&&a[i]<=R) tot++;//cout<<tot<<' ';
        /*
        For(j,m) a[i]+=check(i,j);//,cout<<a[i]<<' ';
        if (L<=a[i]&&a[i]<=R) tot++;//cout<<tot<<' ';
        */
        For(j,m)
        {
            if (c[j]^s[i]) continue;
            if (p[s[i]-'a']-1>=r[j]) add(su[s[i]-'a'][p[s[i]-(int)'a']-r[j]-1]+1,su[s[i]-'a'][p[s[i]-(int)'a']-r[j]],-1);
            if (l[j]&&p[s[i]-'a']-1>=l[j]-1) add(su[s[i]-'a'][p[s[i]-'a']-l[j]]+1,su[s[i]-'a'][p[s[i]-'a']-l[j]+1],1);
        }
        ans+=(long long)tot;
        /*
        cout<<tot<<' '<<endl;
        For(j,i) cout<<a[j]<<' ';cout<<endl;*/
    }
    cout<<ans<<endl;
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值