[ABC273G] Row Column Sums 2

题目传送门

好题呀

解法:

约定:为方便描述,将 “和为 2 2 2 的行”简称为 2 2 2 类行,和为 1 1 1 的简称为 1 1 1 类行,列同理。
题目中虽然指定了每行和每列的和 ,但其实我们只要求出 有对应 行数和列数的方案数即可

设计状态:

f i , j , k : 填了前 i 行,有 j 列为 1 类列, k 列为 2 类列 f_{i,j,k} : 填了前i行,有j列为1类列,k列为2类列 fi,j,k:填了前i行,有j列为1类列,k列为2类列
考虑到前 i i i 行一共要放 ∑ j = 1 i R i \sum_{j=1}^i R_i j=1iRi,记 s u m i = ∑ j = 1 i R i sum_i=\sum_{j=1}^i R_i sumi=j=1iRi,那么明显若已知 j j j , 则 k = s u m i − j 2 k=\frac{sum_i-j}{2} k=2sumij
就可以简化状态:
f i , j : 填了前 i 行,有 j 列为 1 类列, s u m i − j 2 列为 2 类列 f_{i,j} : 填了前i行,有j列为1类列,\frac{sum_i-j}{2}列为2类列 fi,j:填了前i行,有j列为1类列,2sumij列为2类列

状态转移 :

用三维的状态比较好理解转移,改成二维只需去掉 k k k 即可
根据下一列的 R i R_i Ri 转移
f i , j , k → f i + 1 , j , k ( R i + 1 = 0 ) f i , j , k ∗ ( n − j − k ) → f i + 1 , j + 1 , k , f i , j , k ∗ j → f i + 1 , j − 1 , k + 1 ( R i + 1 = 1 ) f i , j , k ∗ C 2 n − j − k → f i + 1 , j + 2 , k , f i , j , k ∗ C 2 j → f i + 1 , j − 2 , k + 2 , f i , j , k ∗ ( n − j − k ) ∗ ( j + 1 ) → f i , j , k + 1 ( R i + 1 = 2 ) \begin{aligned} &f_{i,j,k}\to f_{i+1,j,k} \quad (R_{i+1}=0)\\ &f_{i,j,k}*(n-j-k) \to f_{i+1,j+1,k},f_{i,j,k}*j\to f_{i+1,j-1,k+1} \quad (R_{i+1}=1)\\ &f_{i,j,k}*C_{2}^{n-j-k}\to f_{i+1,j+2,k},f_{i,j,k}*C_{2}^{j}\to f_{i+1,j-2,k+2},f_{i,j,k}*(n-j-k)*(j+1)\to f_{i,j,k+1}\quad(R_{i+1}=2)\\ \end{aligned} fi,j,kfi+1,j,k(Ri+1=0)fi,j,k(njk)fi+1,j+1,k,fi,j,kjfi+1,j1,k+1(Ri+1=1)fi,j,kC2njkfi+1,j+2,k,fi,j,kC2jfi+1,j2,k+2,fi,j,k(njk)(j+1)fi,j,k+1(Ri+1=2)
注意限制条件,比如 f i , j , k ∗ ( n − j − k ) ∗ ( j + 1 ) → f i , j , k + 1 f_{i,j,k}*(n-j-k)*(j+1)\to f_{i,j,k+1} fi,j,k(njk)(j+1)fi,j,k+1 这个转移必须要 j + k < n j+kj+k<n

最后,想想设的状态没有规定每列的和是题目指定的值,只是数量满足了,所以最后要除去排列数
注意代码实现要按之前说的省去第三维 k k k

Code

#include 
#include 
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define _rep(i,j,k) for(int i=k;i>=j;i--)
#define k ((sum[i]-j)/2)
using ll = long long ; 
using db = double ;
using namespace std;
const int N=5e3+7;
const ll mod=998244353,inv2=499122177;
int n,c1;
int R[N],C[N];
ll f[N][N],sum[N],fac[N],ifac[N],ss;
ll qpow(ll ba,ll pow) {
    ll res=1; while(pow) {
        if(pow&1) res=res*ba%mod;
        ba=ba*ba%mod,pow>>=1;
    } return res;
}
ll Add(ll x,ll y) { return ((x+y)%mod) ;}
ll Mul(ll x,ll y) { return ((x*y)%mod) ;}
ll Inv(ll x) { return qpow(x,mod-2) ;}
ll c(ll x,ll y) { return fac[x]*ifac[y]%mod*ifac[x-y]%mod; }
void init() {
    scanf("%d",&n);
    rep(i,1,n) scanf("%d",&R[i]),sum[i]=sum[i-1]+R[i];
    rep(j,1,n) scanf("%d",&C[j]),c1+=(C[j]==1),ss+=C[j];
    fac[0]=1; rep(i,1,n) fac[i]=fac[i-1]*i%mod;
    ifac[n]=Inv(fac[n]); _rep(i,1,n) ifac[i-1]=ifac[i]*i%mod;
}
void work() {
    if(sum[n]!=ss) {puts("0");return ;}
    f[0][0]=1;
    rep(i,0,n) rep(j,0,n) if(sum[i]>=j && j+k<=n){
        if(R[i+1]==0) f[i+1][j]=Add(f[i+1][j],f[i][j]);
        else if(R[i+1]==1) {
            if(k+j1) f[i+1][j-2]=Add(f[i+1][j-2],Mul(f[i][j],j*(j-1)%mod*inv2%mod));
            if(k+j

你可能感兴趣的:(AT,DP杂题,计数DP,算法,动态规划)