zoukankan      html  css  js  c++  java
  • BZOJ5010 FJOI2017矩阵填数(容斥原理)

      如果只考虑某个子矩阵的话,其最大值为v的方案数显然是vsize-(v-1)size。问题在于处理子矩阵间的交叉情况。

      如果两个交叉的子矩阵所要求的最大值不同,可以直接把交叉部分划给所要求的最大值较小的子矩阵。那么,所要求最大值不同的格子彼此间是独立的。于是现在可以只考虑要求相同的格子。

      直接计算似乎很麻烦。由于n很小,考虑一个很套路的容斥:至少0个不满足限制的方案数-至少1个不满足限制的方案数+至少2个不满足限制的方案数……于是我们可以枚举哪些矩阵不满足限制,剩下的随便填(当然要在所限制的最大值之内)。

      计算这些矩形的交和并也是一个有点麻烦的问题。可以离散化后暴力统计。这里离散化后应该每个位置表示一段区间比较方便,所以读入时++x2,++y2。由于数据范围实在太小怎么做都行。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define P 1000000007
    #define N 13
    #define y1 y3
    #define y2 y4
    int T,r,c,n,m,row[N<<1],line[N<<1],flag[N<<1][N<<1],ans,sum,nw,nv;
    bool choose[N];
    struct data
    {
        int x1,y1,x2,y2,v,size;
        int tag[N<<1][N<<1];
        bool operator <(const data&a) const
        {
            return v>a.v;
        }
    }a[N];
    int ksm(int a,int k)
    {
        if (k==0) return 1;
        int tmp=ksm(a,k>>1);
        if (k&1) return 1ll*tmp*tmp%P*a%P;
        else return 1ll*tmp*tmp%P;
    }
    int calc(int v)
    {
        memset(flag,0,sizeof(flag));
        for (int i=1;i<=n;i++)
        if (a[i].v==v&&!choose[i])
            for (int j=a[i].x1;j<a[i].x2;j++)
                for (int k=a[i].y1;k<a[i].y2;k++)
                if (a[i].tag[j][k]) flag[j][k]=1;
        for (int i=1;i<=n;i++)
        if (choose[i])
            for (int j=a[i].x1;j<a[i].x2;j++)
                for (int k=a[i].y1;k<a[i].y2;k++)
                if (a[i].tag[j][k]) flag[j][k]=-1;
        int s1=0,s2=0;
        for (int i=1;i<nw;i++)
            for (int j=1;j<nv;j++)
            if (flag[i][j]==1) s1+=(row[i+1]-row[i])*(line[j+1]-line[j]);
            else if (flag[i][j]==-1) s2+=(row[i+1]-row[i])*(line[j+1]-line[j]);
        return 1ll*ksm(v,s1)*ksm(v-1,s2)%P;
    }
    void dfs(int k,int s,int v)
    {
        if (k>n)
        {
            if (s&1) sum=(sum-calc(v)+P)%P;
            else sum=(sum+calc(v))%P;
            return;
        }
        if (a[k].v==v) choose[k]=1,dfs(k+1,s+1,v);
        choose[k]=0;dfs(k+1,s,v);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj5010.in","r",stdin);
        freopen("bzoj5010.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        T=read();
        while (T--)
        {
            r=read(),c=read(),m=read(),n=read();
            for (int i=1;i<=n;i++) 
            a[i].x1=read(),a[i].y1=read(),a[i].x2=read()+1,a[i].y2=read()+1,a[i].v=read(),a[i].size=0,memset(a[i].tag,0,sizeof(a[i].tag));
            int w=0,v=0;
            for (int i=1;i<=n;i++) 
            row[++w]=a[i].x1,row[++w]=a[i].x2,line[++v]=a[i].y1,line[++v]=a[i].y2;
            row[++w]=1,row[++w]=r+1;line[++v]=1,line[++v]=c+1;
            sort(row+1,row+w+1);sort(line+1,line+v+1);
            nw=unique(row,row+w+1)-row-1,nv=unique(line,line+v+1)-line-1;
            for (int i=1;i<=n;i++)
            a[i].x1=lower_bound(row+1,row+nw+1,a[i].x1)-row,a[i].x2=lower_bound(row+1,row+nw+1,a[i].x2)-row,
            a[i].y1=lower_bound(line+1,line+nv+1,a[i].y1)-line,a[i].y2=lower_bound(line+1,line+nv+1,a[i].y2)-line;
            sort(a+1,a+n+1);
            memset(flag,0,sizeof(flag));
            for (int i=1;i<=n;i++)
                for (int j=a[i].x1;j<a[i].x2;j++)
                    for (int k=a[i].y1;k<a[i].y2;k++)
                    flag[j][k]=a[i].v;
            for (int i=1;i<=n;i++)
                for (int j=1;j<nw;j++)
                    for (int k=1;k<nv;k++)
                    if (flag[j][k]==a[i].v) a[i].size++,a[i].tag[j][k]=1;
            ans=1;
            for (int i=1;i<nw;i++)
                for (int j=1;j<nv;j++)
                if (flag[i][j]==0) ans=1ll*ans*ksm(m,(row[i+1]-row[i])*(line[j+1]-line[j]))%P;
            for (int i=1;i<=n;i++)
            {
                sum=0;int t=i;
                while (a[t+1].v==a[i].v) t++;
                memset(choose,0,sizeof(choose));
                dfs(i,0,a[i].v);
                ans=1ll*ans*sum%P;
                i=t;
            }
            cout<<ans<<endl;
        }
        return 0;
    }
  • 相关阅读:
    HBase-scan API 通过scan读取表中数据
    Servlet总结
    【吴节操点评】中国企业SaaS应用深谙未来者寥寥数几 两极分化将加剧
    hibernate实战笔记1---初探
    POJ
    系统服务-----Activity服务的获取getSystemService
    我的编程之路(二十) 新的环境、新的開始
    王爽《汇编语言》第2版-----2、寄存器
    更新智能开发研发进度
    libcurl实现解析(3)
  • 原文地址:https://www.cnblogs.com/Gloid/p/9471312.html
Copyright © 2011-2022 走看看