zoukankan      html  css  js  c++  java
  • 【Ynoi2016】谁的梦 题解(容斥+STL)

    9月份的时候不知道哪个毒瘤把这道题安排成了**数学专题**的作业题,我感觉这跟数学一点关系也没有……

    题目大意:定义一个序列的权值为不同数字的个数。现在有$n$个序列,我们在每个序列里选一个连续非空子串拼接起来,求所有选法得到的序列权值之和。

    首先考虑容斥(基本套路),考虑每个颜色对答案的贡献,用合法的减去不合法的。设长度为$n$的序列共有$G(n)$个子区间,显然$G(n)=frac{n(n+1)}{2}$。设颜色$c$的总贡献为$sum_c$,则有$sum_c=prodlimits_{i=1}^n G(len_i)-prodlimits_{i=1}^n ans_{c,i}$。其中$ans_{c,i}$表示第$i$个序列里不包含颜色$c$的子区间个数。

    于是问题就变成如何求$ans_{c,i}$。显然如果一个区间不包含颜色$c$,那么这个区间的左右端点一定在两个$c$之间。可以看成颜色$c$将一个序列分成$m$个长度为$l_i$的子序列。则有$ans_{c,i}=sumlimits_{i=1}^m G(l_i)$。设总答案为$ANS$,颜色数为$cnt$,则$ANS=sumlimits_{i=1}^{cnt} prodlimits_{i=1}^n G(len_i)-sumlimits_{i=1}^{cnt} prodlimits_{i=1}^n ans_{c,i}$。

    接下来是实现的问题,毒瘤STL。用一个数组存每种数有多少区间不包含,用STL::map存每个序列里每种数有多少区间不包含。对每一种数开一个STL::set存位置。记得要将数离散化!!!

    一点细节:当序列里只有一种数的时候map值为0,这时候要特判一下。打标记处理即可。

    代码:

    #include<map>
    #include<set>
    #include<vector>
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define int long long
    using namespace std;
    typedef pair<int,int> pii;
    const int p=19260817;
    const int N=200005;
    int a[N],len[N],L[N],R[N],bl[N],inv[N*2],sum[N],P[N],flag[N];
    int tot=1,n,m,ans;
    set<int> s[N];
    map<pii,int> mp;
    vector<int> v;
    struct ask{
        int x,y,z;
    }q[N];
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    template<typename F>
    inline void write(F x, char ed = '
    ') {
        static short st[30];short tp=0;
        if(x<0) putchar('-'),x=-x;
        do st[++tp]=x%10,x/=10; while(x);
        while(tp) putchar('0'|st[tp--]);
        putchar(ed);
    }
    inline int G(int len){
        return (len*(len-1)>>1)%p;
    }
    inline int INV(int i){
        return (i<300000)?inv[i]:(p-p/i)*INV(p%i)%p;
    }
    inline void insert(int col,int pos)
    {
        int pre=*--s[col].lower_bound(pos),suf=*s[col].upper_bound(pos);
        pre=max(pre,L[bl[pos]]-1),suf=min(suf,R[bl[pos]]+1);
        const pii xx=make_pair(bl[pos],col);
        if (!mp.count(xx)) mp[xx]=G(len[bl[pos]]+1);
        int &v=mp[xx];
        ans=(ans+(flag[col]?0:sum[col]))%p;
        sum[col]=sum[col]*INV(v)%p;
        v=(v-G(suf-pre)+G(pos-pre)+G(suf-pos)+p)%p;
        if (v) sum[col]=sum[col]*v%p;
        else ++flag[col];
        ans=(ans-(flag[col]?0:sum[col])+p)%p;
        s[col].insert(pos);
    }
    inline void erase(int col,int pos)
    {
        int pre=*--s[col].lower_bound(pos),suf=*s[col].upper_bound(pos);
        pre=max(pre,L[bl[pos]]-1),suf=min(suf,R[bl[pos]]+1);
        const pii xx=make_pair(bl[pos],col);
        if (!mp.count(xx)) mp[xx]=G(len[bl[pos]]+1);
        int &v=mp[xx];
        ans=(ans+(flag[col]?0:sum[col]))%p;
        if (!v) --flag[col];
        else sum[col]=sum[col]*INV(v)%p;
        v=(v+G(suf-pre)-G(pos-pre)-G(suf-pos)+p+p)%p;
        sum[col]=sum[col]*v%p;
        ans=(ans-(flag[col]?0:sum[col])+p)%p;
        s[col].erase(pos);
    }
    signed main()
    {
        n=read();m=read();
        inv[1]=1;
        for (int i=2;i<300000;i++) inv[i]=(p-p/i)*inv[p%i]%p;
        for (int i=1;i<=n;i++)
        {
            len[i]=read();
            L[i]=R[i-1]+1,R[i]=R[i-1]+len[i];
            tot=tot*G(len[i]+1)%p;P[i]=P[i-1]+len[i]; 
        }
        for (int i=1;i<=n;i++)
            for (int j=L[i];j<=R[i];j++)
                bl[j]=i,a[j]=read(),v.push_back(a[j]);
        for (int i=1;i<=m;i++){
            q[i].x=read(),q[i].y=read(),q[i].z=read();
            v.push_back(q[i].z);
        }
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());
        for (int i=0;i<v.size();i++)
            s[i].insert(0),s[i].insert(R[n]+1),sum[i]=tot;
        for (int i=1;i<=R[n];i++){
            a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin();
            insert(a[i],i);
        }
        write(ans);
        for (int i=1;i<=m;i++)
        {
            const int id=P[q[i].x-1]+q[i].y;
            erase(a[id],id);
            a[id]=lower_bound(v.begin(),v.end(),q[i].z)-v.begin();
            insert(a[id],id);
            write(ans);
        }
        return 0;
    }
  • 相关阅读:
    函数依赖(转)
    C++对象的深拷贝和浅拷贝
    C++临时匿名对象
    C++操作符重载
    C数组和指针
    动态开发入门之Servlet
    数据库的CURD操作 以及经典的sql语句
    如何删除07版word页眉页脚的横线
    数据库的连接查询
    经典面试题 详细解析Java中抽象类和接口的区别
  • 原文地址:https://www.cnblogs.com/Invictus-Ocean/p/13922005.html
Copyright © 2011-2022 走看看