五校联考R1 Day2T2 矩阵matrix(容斥)

题目链接

容易想到容斥,但是很恶心,因为要对行和列都容斥,然后行+列又要容斥。。
于是得到\(O(nm\log)\)的做法。
就有70分了:

#include <cstdio>
#include <algorithm>
#define mod (1000000007)
#define Mod(x) (x>mod&&(x-=mod))//>=
#define ID(x,y) ((x-1)*m+y)
typedef long long LL;
const int N=1e5+5,M=1005;

int n,m;

namespace Subtask1
{
    int Cn[N],Cm[N],inv[N];
    inline LL FP(LL x,LL k)
    {
        LL t=1;
        for(; k; k>>=1,x=x*x%mod)
            if(k&1) t=t*x%mod;
        return t;
    }
    LL Calc(LL n,LL m,int *C)
    {
        LL res=0;
        for(int i=1; i<=n; ++i)
            if(i&1) res+=1ll*C[i]*FP(2,(n-i)*m)%mod;
            else res-=1ll*C[i]*FP(2,(n-i)*m)%mod;
        return (res%mod+mod)%mod;
    }
    LL Unique(LL n,LL m)
    {
        LL res=0;
        for(int i=1; i<=n; ++i)
            for(int j=1; j<=m; ++j)
                if((i+j)&1) res+=1ll*Cn[i]*Cm[j]%mod*FP(2,(n-i)*(m-j))%mod;
                else res-=1ll*Cn[i]*Cm[j]%mod*FP(2,(n-i)*(m-j))%mod;
        return (res%mod+mod)%mod;
    }
    void Main(int n,int m)
    {
        Cn[0]=Cm[0]=inv[1]=1;
        for(int i=2,l=std::max(n,m); i<=l; ++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
        for(int i=1; i<=n; ++i) Cn[i]=1ll*Cn[i-1]*(n-i+1)%mod*inv[i]%mod;
        for(int i=1; i<=m; ++i) Cm[i]=1ll*Cm[i-1]*(m-i+1)%mod*inv[i]%mod;
//      printf("%I64d-%I64d-%I64d-%I64d\n",FP(2,1ll*n*m),Calc(n,m,Cn),Calc(m,n,Cm),Unique(n,m)-mod);
        printf("%I64d\n",((FP(2,1ll*n*m)-(Calc(n,m,Cn)+Calc(m,n,Cm)+Unique(n,m))%mod)%mod+mod)%mod);
    }
}
namespace TEST
{
    int Ans;
    bool col[1005][1005],vis[20000001];
    bool Checkr()//存在某行未染色的方案数 
    {
        for(int i=1; i<=n; ++i)
        {
            for(int j=m; ~j; --j)
                if(!j) return 1;
                else if(col[i][j]) break;
        }
        return 0;
    }
    bool Checkc()//存在某列未染色的方案数 
    {
        for(int j=1; j<=m; ++j)
        {
            for(int i=n; ~i; --i)
                if(!i) return 1;
                else if(col[i][j]) break;
        }
        return 0;
    }
    void DFS(int x,int y,int s)
    {
        if(y>m) y=1, ++x;
        if(x>n)
        {
            if(!vis[s]&&Checkc())
            {
                puts("\nOK:");
                for(int i=1; i<=n; ++i,putchar('\n'))
                    for(int j=1; j<=m; ++j) printf("%d ",col[i][j]);
                ++Ans, vis[s]=1;
            }
            return;
        }
        DFS(x,y+1,s), col[x][y]=1, DFS(x,y+1,s|(1<<ID(x,y)-1)), col[x][y]=0;
    }
    void Main()
    {
        DFS(1,1,0), printf("%d\n",Ans);
    }
}

int main()
{
    freopen("matrix.in","r",stdin);
    freopen("matrix.out","w",stdout);

    scanf("%d%d",&n,&m);
    if(m==1) return putchar('1'),0;
//  if(n==100000&&m==100000) return printf(""),0;//可能要跑2h。。没早打表
//  TEST::Main();
    if(n<=1000&&m<=1000||1ll*n*m<=1400000||1) {Subtask1::Main(n,m); return 0;}

    return 0;
}

其实只要保证列合法,只对行容斥就可以了。
当确定\(k\)行不染色时,每列合法的方案数是\(2^{n-k}-1\),然后\(m\)列的方案数就是它的\(m\)次方。

#include <cstdio>
#include <algorithm>
#define mod (1000000007)
typedef long long LL;
const int N=1e5+5;

int inv[N],C[N];

inline LL FP(LL x,LL k)
{
    x<0&&(x+=mod);
    LL t=1;
    for(; k; k>>=1,x=x*x%mod)
        if(k&1) t=t*x%mod;
    return t;
}
LL Calc(LL n,LL m)
{
    LL res=0;
    for(int i=0; i<=n; ++i)
        if(i&1) res-=1ll*C[i]*FP(FP(2,n-i)-1,m)%mod;
        else res+=1ll*C[i]*FP(FP(2,n-i)-1,m)%mod;
    return (res%mod+mod)%mod;
}

int main()
{
    freopen("matrix.in","r",stdin);
    freopen("matrix.out","w",stdout);

    int n,m; scanf("%d%d",&n,&m);
    C[0]=inv[1]=1;
    for(int i=2; i<=n; ++i) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
    for(int i=1; i<=n; ++i) C[i]=1ll*C[i-1]*(n-i+1)%mod*inv[i]%mod;
    printf("%I64d\n",Calc(n,m));

    return 0;
}

转载于:https://www.cnblogs.com/SovietPower/p/9540065.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值