Loading

[ARC143B] Counting Grids 题解

Counting Grids

题目大意#

1n2 填入 n×n 的网格 A 中,对于每个格子满足以下条件之一:

  • 该列中存在大于它的数。

  • 该行中存在小于它的数。

求方案数。

思路分析#

首先有一个比较显然的结论:对于一个不合法的方案,有且仅有一个数不满足任何一个条件。

考虑反证法,假设有两个数都不满足任何一个条件,设这两个数分别位于 (x1,y1),(x2,y2),则有:Ax1,y1>Ax1,y2>Ax2,y2Ax2,y2>Ax2,y1>Ax1,y1,存在矛盾,而多个数的情况可以归纳为两个数的情况,故结论成立。

正难则反,考虑计算不合法的方案数:

设不满足任何条件的数为 i,考虑到 i 是所在列中最大的数,且是所在行中最小的数,故所在行的填法为 An2in1,所在列的填法为 Ai1n1,其他的地方随便填,一定满足条件,填法为 (n1)2!,再考虑 i 的位置,故得出不合法的方案数的计算式为:

n2×(n1)2!×i=nn2n+1An2in1Ai1n1

那么合法的方案数只需要用 n2! 减一下就可以了。

如果预处理阶乘和阶乘逆元,那么计算的时间复杂度为 O(n2)

代码#

#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdio>

using namespace std;
const int N=250100,V=250000,mod=998244353;
#define int long long

int fac[N],inv[N];
int n,ans;

int q_pow(int a,int b){
    int res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}

int A(int n,int m){
    if(n<m) return 0;
    return fac[n]*inv[n-m]%mod;
}

signed main(){
    scanf("%lld",&n);
    int n2=n*n;
    fac[0]=1;
    for(int i=1;i<=n2;i++) fac[i]=fac[i-1]*i%mod;
    inv[n2]=q_pow(fac[n2],mod-2);
    for(int i=n2;i>=1;i--) inv[i-1]=inv[i]*i%mod;
    for(int i=n;i<=n2-n+1;i++) 
        ans=(ans+A(n2-i,n-1)*A(i-1,n-1)%mod)%mod;
    ans=(ans*fac[(n-1)*(n-1)]%mod)*n2%mod;
    ans=(fac[n*n]-ans+mod)%mod;
    cout<<ans<<'\n';
    return 0;
}

作者:TKXZ133

出处:https://www.cnblogs.com/TKXZ133/p/17583398.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   TKXZ133  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
more_horiz
keyboard_arrow_up light_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示