题目传送门:bzoj4806

  这种题一看就是dp。。。我们可以设$ f[i][j][k] $表示处理到第$ i $行,有$ j $列没放炮,$ k $列只放了一个炮。接着分情况讨论:第$ i $行不放炮、放一个炮、放两个炮;放在只有一个炮的列上,还是放在没炮的列上。于是就可以快乐地列方程了:

  $ \begin{equation} \begin{split} f[i][j][k] &= f[i-1][j][k] \\ &+ (j+1)\cdot f[i-1][j+1][k-1] \\ &+ (k+1)\cdot f[i-1][j][k+1] \\ &+ \binom{j+2}{2} \cdot f[i-1][j+2][k-2] \\ &+ (j+1)\cdot k\cdot f[i-1][j+1][k] \\ &+ \binom{k+2}{2}\cdot f[i-1][j][k+2] \end{split} \end{equation} $

  另外,此题有双倍经验:bzoj1801(我是不会告诉你模数不一样的)

  代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#include<queue>
#include<vector>
#define ll long long
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define inf 0x7fffffff
#define mod 999983
#define eps 1e-20
ll read()
{
    ll tmp=0; char c=getchar(),f=1;
    for(;c<'0'||'9'<c;c=getchar())if(c=='-')f=-1;
    for(;'0'<=c&&c<='9';c=getchar())tmp=tmp*10+c-'0';
    return tmp*f;
}
using namespace std;
ll f[110][110][110];
int n,m;
int main()
{
    int i,j,k;
    n=read(); m=read();
    f[0][m][0]=1;
    for(i=1;i<=n;i++)
        for(j=0;j<=m;j++)
            for(k=0;k+j<=m;k++){
                f[i][j][k]=f[i-1][j][k]+f[i-1][j][k+1]*(k+1)+f[i-1][j][k+2]*(k+2)*(k+1)/2+f[i-1][j+1][k]*k*(j+1);
                if(k)f[i][j][k]+=f[i-1][j+1][k-1]*(j+1);
                if(k>1)f[i][j][k]+=f[i-1][j+2][k-2]*(j+2)*(j+1)/2;
                f[i][j][k]%=mod;
            }
    ll ans=0;
    for(j=0;j<=m;j++)
        for(k=0;k+j<=m;k++)
            ans=(ans+f[n][j][k])%mod;
    printf("%lld\n",ans); 
}
bzoj4806

相关文章:

  • 2021-05-26
  • 2022-02-11
  • 2021-06-17
  • 2021-07-19
  • 2022-01-29
  • 2022-12-23
  • 2022-12-23
  • 2021-07-17
猜你喜欢
  • 2022-01-30
  • 2021-11-30
  • 2021-12-11
  • 2021-07-08
  • 2021-09-12
  • 2022-01-08
  • 2021-08-13
相关资源
相似解决方案