[BZOJ3294] put chess pieces (dynamic planning, tolerance and exclusion, Combinatorial Mathematics)

Problem surface

BZOJ
Luo Gu

Title Solution

If a row or a column is occupied by a certain color, you can directly discard these rows and columns when considering other rows.
So we can write a dpdp
Let f[i][r][c]f[i][r][c] indicate that the first two colors are considered, and the remaining rr row cc column is not stained.
So when transferring, enumerate the current color stained aa row bb column transfer.
But the problem is, how to calculate the number of schemes that use KK pieces to cover aa rows and bb columns?
It's just not easy to calculate. Let's change it to cover at most the number of schemes in row aa and column bb.
So it's easy to figure out this is CKabCabK.
Then we can calculate the number of schemes that exactly cover row aa and column bb.
When we calculate a, Ba and B, we can calculate the number of schemes that cover L, l < Al, l < a row, R < BR, R < B column,
Then just subtract the illegal from the total.
Next is a very simple dpdp. Just use the combination number a little.

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long
#define MOD 1000000009
#define MAX 35
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
int n,m,c,ans;
int f[MAX][MAX][MAX],a[MAX];
int jc[MAX*MAX],jv[MAX*MAX],inv[MAX*MAX];
int g[MAX][MAX][MAX];
int C(int n,int m){if(m>n)return 0;return 1ll*jc[n]*jv[m]%MOD*jv[n-m]%MOD;}
int main()
{
    n=read();m=read();c=read();
    for(int i=1;i<=c;++i)a[i]=read();
    jc[0]=inv[0]=inv[1]=jv[0]=1;
    for(int i=1;i<=n*m;++i)jc[i]=1ll*jc[i-1]*i%MOD;
    for(int i=2;i<=n*m;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
    for(int i=1;i<=n*m;++i)jv[i]=1ll*jv[i-1]*inv[i]%MOD;
    for(int i=1;i<=c;++i)
        for(int j=1;j<=n;++j)
            for(int k=1;k<=m;++k)
            {
                if(j*k<a[i])continue;
                g[i][j][k]=C(j*k,a[i]);
                for(int l=1;l<=j;++l)
                    for(int r=1;r<=k;++r)
                        if(l!=j||r!=k)add(g[i][j][k],MOD-1ll*C(j,l)*C(k,r)%MOD*g[i][l][r]%MOD);
            }
    f[0][0][0]=1;
    for(int i=1;i<=c;++i)
        for(int j=1;j<=n;++j)
            for(int k=1;k<=m;++k)
                for(int a=1;a<=j;++a)
                    for(int b=1;b<=k;++b)
                        add(f[i][j][k],1ll*g[i][a][b]*f[i-1][j-a][k-b]%MOD*C(n-j+a,a)%MOD*(C(m-k+b,b))%MOD);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j)add(ans,f[c][i][j]);
    printf("%d\n",ans);
    return 0;
}

Posted on Fri, 10 Jan 2020 11:35:08 -0500 by SouThPaw09