码迷,mamicode.com
首页 > 其他好文 > 详细

[CF930E]/[CF944G]Coins Exhibition

时间:2018-05-23 20:45:11      阅读:376      评论:0      收藏:0      [点我收藏+]

标签:unique   i+1   长度   离散化   html   blog   const   关键点   线性   

[CF930E]/[CF944G]Coins Exhibition

题目地址:

CF930E/CF944G

博客地址:

[CF930E]/[CF944G]Coins Exhibition - skylee

题目大意:

一个长度为\(k(k\le10^9)\)\(01\)串,给出\(n+m(n,m\le10^5)\)个约束条件,其中\(n\)条描述区间\([l_i,r_i]\)至少有一个\(0\),其中\(m\)条描述区间\([l_i,r_i]\)至少有一个\(1\)。求合法的\(01\)串数量。

思路:

显然直接考虑所有的\(k\)位,就算\(\mathcal O(k)\)的线性算法也会超时,因此对于所有的\(l_i-1,r_i\)以及\(0,k\)离散化以后考虑这些关键点即可。

设关键点有\(lim\)个,对所有关键点排序,\(tmp[i]\)\(i\)离散化前对应的数。对所有关键点排序,考虑动态规划,设\(f[i][j\in\{0,1,2\}]\)表示从后往前考虑第\(i\sim lim\)个关键点。若\(j\in\{0,1\}\),则\(f[i][j]\)表示\(tmp[i]\sim tmp[i+1]\)中含有\(j\)的方案数后缀和。若\(j=2\),则\(f[i][j]\)表示最后一段同时有\(0\)\(1\)的方案数。用\(min[j\in\{0,1\}][i]\)表示对应约束条件类型为\(j\)\(i\)右侧最近的、对应左端点不在\(i\)左侧的右端点。状态转移方程如下:

  • \(f[i][0]=f[i+1][0]+f[i+1][1]-f[min[1][i]][1]+f[i+1][2]\times(2^{tmp[i+1]-tmp[i]}-2)\)
  • \(f[i][1]=f[i+1][1]+f[i+1][0]-f[min[0][i]][0]+f[i+1][2]\times(2^{tmp[i+1]-tmp[i]}-2)\)
  • \(f[i][2]=f[i+1][0]-f[min[0][i]][0]+f[i+1][1]-f[min[1][i]][1]+f[i+1][2]\times(2^{tmp[i+1]-tmp[i]}-2)\)

最终答案为\(f[0][2]\)

时间复杂度\(\mathcal O((n+m)(\log(n+m)+\log k))\)。其中\(\mathcal O(\log(n+m))\)为离散化复杂度,\(\mathcal O(\log k)\)为快速幂复杂度。

源代码:

#include<cstdio>
#include<cctype>
#include<algorithm>
using int64=long long;
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
constexpr int N=1e5,mod=1e9+7;
std::pair<int,int> p[2][N];
int tmp[N*4+2],min[2][N*4+2],f[N*4+2][3];
inline int power(int a,int k) {
    int ret=1;
    for(;k;k>>=1) {
        if(k&1) ret=(int64)ret*a%mod;
        a=(int64)a*a%mod;
    }
    return ret;
}
int main() {
    const int k=getint(),n=getint(),m=getint();
    int lim=0;
    for(register int i=0;i<n;i++) {
        tmp[++lim]=p[0][i].first=getint()-1;
        tmp[++lim]=p[0][i].second=getint();
    }
    for(register int i=0;i<m;i++) {
        tmp[++lim]=p[1][i].first=getint()-1;
        tmp[++lim]=p[1][i].second=getint();
    }
    tmp[++lim]=k;
    std::sort(&tmp[0],&tmp[lim]+1);
    lim=std::unique(&tmp[0],&tmp[lim]+1)-&tmp[1];
    for(register int i=0;i<=lim;i++) {
        min[0][i]=min[1][i]=lim+1;
    }
    for(register int i=0;i<n;i++) {
        p[0][i].first=std::lower_bound(&tmp[0],&tmp[lim]+1,p[0][i].first)-tmp;
        p[0][i].second=std::lower_bound(&tmp[0],&tmp[lim]+1,p[0][i].second)-tmp;
        min[0][p[0][i].first]=std::min(min[0][p[0][i].first],p[0][i].second);
    }
    for(register int i=0;i<m;i++) {
        p[1][i].first=std::lower_bound(&tmp[0],&tmp[lim]+1,p[1][i].first)-tmp;
        p[1][i].second=std::lower_bound(&tmp[0],&tmp[lim]+1,p[1][i].second)-tmp;
        min[1][p[1][i].first]=std::min(min[1][p[1][i].first],p[1][i].second);
    }
    for(register int i=lim;i;i--) {
        min[0][i-1]=std::min(min[0][i-1],min[0][i]);
        min[1][i-1]=std::min(min[1][i-1],min[1][i]);
    }
    f[lim][0]=f[lim][1]=f[lim][2]=1;
    for(register int i=lim-1;i>=0;i--) {
        int g[3];
        g[0]=(f[i+1][0]-f[min[0][i]][0]+mod)%mod;
        g[1]=(f[i+1][1]-f[min[1][i]][1]+mod)%mod;
        g[2]=(int64)f[i+1][2]*((power(2,tmp[i+1]-tmp[i])-2+mod)%mod)%mod;
        f[i][0]=((int64)f[i+1][0]+g[1]+g[2])%mod;
        f[i][1]=((int64)f[i+1][1]+g[0]+g[2])%mod;
        f[i][2]=((int64)g[0]+g[1]+g[2])%mod;
    }
    printf("%d\n",f[0][2]);
    return 0;
}

[CF930E]/[CF944G]Coins Exhibition

标签:unique   i+1   长度   离散化   html   blog   const   关键点   线性   

原文地址:https://www.cnblogs.com/skylee03/p/9078791.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!