zoukankan      html  css  js  c++  java
  • 2019.11.11 洛谷月赛t3

    题目背景

    由于Y校的老师非常毒瘤,要求(zhouwc)(csp)考前最后(3)天参加期中考,(zhouwc)非常生气,决定消极考试,以涂完卡但全错为目标。现在(retcarizy)(zhouwc)太可怜了,想要帮(zhouwc)解决一个问题,但他自己又太忙了,咕咕咕,于是就把问题甩给了你。

    题目描述

    给你一个长度为(n)的字符串(S)

    (m)个操作,保证(mleq n)

    你还有一个字符串(T),刚开始为空。

    共有两种操作。

    第一种操作:

    在字符串(T)的末尾加上一个字符。

    第二种操作:

    在字符串(T)的开头加上一个字符。

    每次操作完成后要求输出有几个(l in [1,T.size])满足以下条件:

    对于(forall i in [1,l])(T_{T.size-l+i} e S_{i})

    (Tip:)字符串下标从(1)开始。(T.size)表示(T)的长度。

    输入格式

    第一行两个正整数(n,m)

    第二行(n)个正整数,用空格隔开,第(i)个整数表示(S_i)

    接下来(m)行,每行两个数字(opt,ch)(opt=0)表示在(T)的末尾加一个字符(ch),(opt=1)表示在(T)的开头加一个字符(ch)

    输出格式

    (m)行,每行一个非负整数表示第(m)操作后的输出。

    输入输出样例

    输入 #1

    10 3
    1 2 3 1 2 3 2 3 2 3
    0 1
    1 2
    0 3
    

    输出 #1

    0
    1
    1
    

    说明/提示

    注意:本题采用捆绑测试,只有当你通过一个subtask的所有点后,你才能拿到这个subtask的分数

    对于所有的数据 (n leq 10^6,m leq 3.3333 imes 10^4,|sum|leq10^3,S_i in [1,|sum|])((sum)表示字符集)

    (subtask1(17\%)):(m leq 333)

    (subtask2(33\%):m leq 3333)

    (subtask3(20\%):|sum|leq2∣)

    (subtask4(30\%):)无特殊条件

    样例解释:

    第一次操作后,(T=“1”),

    (l=1)(T[1]=S[1]),所以答案为你不jjgvfj(0)

    第二次操作后,(T=“21”),

    (l=1)时,(T[2]=S[1])

    (l=2)时,(T[1]!=S[1])(T[2]!=S[2]),所以答案为(1)

    第三次操作后,(T=“213”),

    (l=1)时,(T[3]!=S[1]);

    (l=2)时,(T[2]=S[1]);

    (l=3)时,(T[3]=S[3]),所以答案为(1)

    (O(m^3))的做法很容易想,按照题意模拟即可。预计得分(17pts)

    对于(O(m^2))的做法,因为这个题实际上是查找(S)的前(l)个和(T)的后(l)个是否严格不相等,我们考虑记录(dp[l])表示在上述意义下(l)是否合法。容易知道,在(T)串最后插入一个字符时,因为(S)串始终不变,(T)串的最后(l)个字符从原本(T)串的后(l)个字符变成了原本(T)串的后(l-1)个字符加上新加入的字符,所以为了比较新的(T)串后(l)个字符是否合法,我们只需要比较新字符、原本(T)串的后(l-1)个字符是否相等即可。即(dp[i]=dp[i-1]|(ch==S[i]))。这样,对于每个加入的字符,只需要用(O(1))的复杂度检查每个枚举到的(l)是否合法即可。

    (T)串最前面插入一个字符时,因为原本所有的合法的(l)依然没有变化,只是增加了一个新的(l),所以我们只需暴力(check)新加入的答案(l),对于每一位枚举是否不同即可。

    时间复杂度(O(m^2)),预计得分(50pts)。是我在考场上想出来的方法。

    考虑优化(O(m^2))的做法,我们找到了状压神器——(bitset),它可以将复杂度优化到原来的(frac{1}{32})。如果常数优秀一些这个方法可以过。

    考虑刚才的方法算过了哪些不可能合法的状态,我们知道所有的字符其存在位置都是独立的,所以我们用一个(bitset)数组(id[i])记录字符(i)在哪些位置上出现过。只要加入的新数(dt)对应的位置是(id[dt])(1)的位置,则该状态肯定不合法。

    所以这样优化的关键在于同时算出了所有合法的状态。所以我们用(f)的第(i)位的(0/1)表示后缀长度为(i)时是否合法。

    如果在(T)串尾部加入新的字符,则对于长度是(i)的情况一定是由(i-1)的情况和新加入位的情况同时转移来(见上述(O(n^2))做法),而所有新加入的位对应与(S)串中哪些位相同已经存储好,假设加入的字符是(dt),则(f=(f<<1)|id[dt])

    如果在(T)串头部加入新的字符,设原来(T)串有效的后缀长度有(l)位,则新的(T)串后(l)位是否合法状态不变,所以新旧(T)串前面(l)位答案一样;

    (T)串头部插入新字符时,我们发现遇到了一些新的问题:

    第一,我们发现在头部加入字符时,后面的所有字符都往后移了一位。

    第二,我们需要比较加入的新字符和第一个字符是否相同。

    很明显困难在于解决第一个问题。因为我们如果要想比较移动之后的字符和(S)的关系,在不知道其它任何东西的情况下,需要另用一个(O(n))检查。

    解决这个问题的方法是一个非常重要的思想:费用提前。在每次从队尾加入一个字符时,我们将这个字符所能贡献到答案的所有位置一次存好。方法很简单,假设我们每次加进的字符是(dt),考虑这一位对应到(S)串的所有可能。如果(dt)对应到的某一位上(id[dt])在同样的位上恰好是(1),说明当队尾不断加入字符使当前这个(dt)恰好对应到刚才说的这一位上,则这样的方案肯定是不合法的。

    考虑如何进行这样的操作。假设(dt)是在第(i)位加入队列,则(dt)(T)结尾的长度是(i-1)。注意这里我们只讨论(T)序列结尾的费用提前,因为其它点情况和结尾一样。假设(dt)对应的(id)值在第(k)位上是(1),说明(dt)在取到第(k)位时整体一定不合法。这时(dt)距离队尾的距离是(l-1),所以(dt)的位置由队尾左移(i-1)位得到,所以当(dt)取到(k)时,队尾应该取到(k+l-1)位,但是注意是反着存的,所以:

    [f=f|(id[dt]<<x-1) ]

    上代码:

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<bitset>
    using namespace std;
    int n,m,opt,S[1000005],dt;
    bitset<35005> f,id[1005],now;
    int read(){
        int ans=0;
        char ch=getchar();
        while(ch<'0'||ch>'9')
            ch=getchar();
        while(ch<='9'&&ch>='0'){
            ans=ans*10+ch-'0';
            ch=getchar();
        }
        return ans;
    }
    int main(){
        n=read();
        m=read();
        for(int i=1;i<=n;i++)
            S[i]=read();
        for(int i=1;i<=m;i++)
            id[S[i]].set(i);
        now.set();
        for(int i=1;i<=m;i++){
            opt=read();
            dt=read();
            now.reset(i);
            if(opt==0)
                f=(f<<1)|id[dt];
            else
                f=f|(id[dt]<<(i-1));
            printf("%d
    ",(~(f|now)).count());
        }
        return 0;
    }
    
  • 相关阅读:
    WCF 客户端调用几种方式
    Mes首检确认统计的存储过程
    C#调用webService的几种方法
    负载均衡SESSION同步总结
    CCF201604-3 路径解析(解法三)(90分)
    CCF201604-3 路径解析(解法三)(90分)
    CCF201604-3 路径解析(解法二)(100分)
    CCF201604-3 路径解析(解法二)(100分)
    CCF201604-3 路径解析(100分)
    CCF201604-3 路径解析(100分)
  • 原文地址:https://www.cnblogs.com/qxds/p/11837850.html
Copyright © 2011-2022 走看看