noip十连测day5-狗

题目描述

小G养了很多狗。

小G一共有 n × n n\times n n×n 条狗,在一个矩阵上。小G想让狗狗交朋友,一条狗狗最多只能交一个朋友,不必所有狗狗都有朋友。但是狗狗交朋友有要求,具体的,第 i i i 行第 j j j 列的狗有两个值 d i , j ∈ { U,D,L,R } d_{i,j}\in\{\texttt{U,D,L,R}\} di,j∈{U,D,L,R} 表示它只能和上/下/左/右的狗狗交朋友,如果成功交友能得到 a i , j a_{i,j} ai,j 的喜悦值。一个交友方案的价值就是所有有朋友的狗狗的喜悦值之和。

小G想知道所有交友方案的价值和,由于这个数可能很大,请对 998244353 998244353 998244353 取模并告诉小G。

朋友关系是双向的,两条狗互相交朋友需要两个d都满足,上下左右不必相邻

上下左右是指正上/正下/正左/正右,也就是要在同一行同一列


很显然,只有在一行中左 R R R 右 L L L,在一列中上 D D D 下 U U U,才会匹配成功。所以每一行列之间是独立,互不干扰的。

考虑一行的情况做动态规划。其他行列的情况类似。

设状态 f i , j , g i , j f_{i,j},g_{i,j} fi,j,gi,j 表示前 i i i 个,选了若干个 R R R 狗,还有 j j j 个 R R R 狗未匹配,此时的方案数,权值和。

初始状态 f 0 , 0 = 1 f_{0,0}=1 f0,0=1

分类讨论转移

  • 不选当前狗

    则 f i , j = f i , j + f i − 1 , j f_{i,j}=f_{i,j}+f_{i-1,j} fi,j=fi,j+fi−1,j, g i , j = g i , j + g i − 1 , j g_{i,j}=g_{i,j}+g_{i-1,j} gi,j=gi,j+gi−1,j

  • 选了当前狗,是 L L L

    方案数:此时可以在 j + 1 j+1 j+1 个未匹配的 R R R 任选一个与当前的 L L L 匹配, j + 1 j+1 j+1 种方案。
    f i , j = f i , j + f i − 1 , j + 1 ⋅ ( j + 1 ) f_{i,j}=f_{i,j}+f_{i-1,j+1}\cdot(j+1) fi,j=fi,j+fi−1,j+1⋅(j+1)

    权值和:有 j + 1 j+1 j+1 种方案,每一种方案要加上 a i a_i ai 乘上方案数。
    g i , j = g i , j + ( j + 1 ) ( g i − 1 , j + 1 + f i − 1 , j + 1 ⋅ a i ) g_{i,j}=g_{i,j}+(j+1)(g_{i-1,j+1}+f_{i-1,j+1}\cdot a_i) gi,j=gi,j+(j+1)(gi−1,j+1+fi−1,j+1⋅ai)

  • 选了当前狗,是 R R R

    方案数:加上上一个。
    f i , j = f i , j + f i − 1 , j − 1 f_{i,j}=f_{i,j}+f_{i-1,j-1} fi,j=fi,j+fi−1,j−1

    权值和:加上 a i a_i ai 乘上方案数。
    g i , j = g i , j + g i − 1 , j − 1 + f i − 1 , j − 1 ⋅ a i g_{i,j}=g_{i,j}+g_{i-1,j-1}+f_{i-1,j-1}\cdot a_{i} gi,j=gi,j+gi−1,j−1+fi−1,j−1⋅ai

至此,我们已经求出每一行列的情况。(行列本质是一样的)

一行(列)求出权值和在答案的出现次数是其他行列的方案数之积。(易证)

时间复杂度 O ( n 3 ) O(n^3) O(n3)

代码如下

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=998244353;
int n,a[501][501],cnt,c[510];
char d[510][510],b[510];
ll f[501][501],g[501][501],ans;
pair<ll,ll> num[1001];
pair<ll,ll> calc(char b[],int a[])
{
    int n=strlen(b+1);
    memset(f,0,sizeof(f));
    memset(g,0,sizeof(g));
    f[0][0]=1;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=n;j++){
            (f[i][j]+=f[i-1][j])%=mod;
            (g[i][j]+=g[i-1][j])%=mod;
            if(b[i]=='L'||b[i]=='U'){
                (f[i][j-1]+=f[i-1][j]*(j))%=mod;
                (g[i][j-1]+=g[i-1][j]*(j)+f[i-1][j]*a[i]%mod*(j))%=mod;
            }
            else{
                (f[i][j+1]+=f[i-1][j])%=mod;
                (g[i][j+1]+=g[i-1][j]+f[i-1][j]*a[i])%=mod;
            }
        }
    }
    return make_pair(f[n][0],g[n][0]);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%s",d[i]+1);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%d",&a[i][j]);
        }
    }
    for(int i=1;i<=n;i++){
        memset(b,0,sizeof(b));
        int t=0;
        for(int j=1;j<=n;j++){
            if(d[i][j]=='L'||d[i][j]=='R'){
                b[++t]=d[i][j];
                c[t]=a[i][j];
            }
        }
        if(t) num[++cnt]=calc(b,c);
    }
    for(int i=1;i<=n;i++){
        memset(b,0,sizeof(b));
        int t=0;
        for(int j=1;j<=n;j++){
            if(d[j][i]=='U'||d[j][i]=='D'){
                b[++t]=d[j][i];
                c[t]=a[j][i];
            }
        }
        if(t) num[++cnt]=calc(b,c);
    }
    for(int i=1;i<=cnt;i++){
        ll x=num[i].second;
        for(int j=1;j<=cnt;j++) if(i!=j) x=x*num[j].first%mod;
        ans=(ans+x)%mod;
    }
    cout<<ans;
}
相关推荐
迷迭所归处2 小时前
动态规划 —— 子数组系列-单词拆分
算法·动态规划
飞滕人生TYF1 天前
动态规划 详解
算法·动态规划
SSL_lwz1 天前
P11290 【MX-S6-T2】「KDOI-11」飞船
c++·学习·算法·动态规划
ZZZ_O^O1 天前
【动态规划-卡特兰数——96.不同的二叉搜索树】
c++·学习·算法·leetcode·动态规划
橘子遇见BUG2 天前
算法日记 31 day 动态规划(01背包)
算法·动态规划
我是哈哈hh2 天前
专题二十二_动态规划_子序列系列问题(数组中不连续的一段)_算法专题详细总结
数据结构·c++·算法·动态规划·子序列
橘子遇见BUG2 天前
算法日记 30 day 动态规划(背包问题)
算法·动态规划
是糖不是唐2 天前
代码随想录算法训练营第五十二天|Day52 图论
c语言·算法·深度优先·动态规划·图论
Lindsey_feiren2 天前
代码随想录day44算法随想录|动态规划07
算法·动态规划
姜西西_3 天前
动态规划 之 子序列系列 算法专题
算法·动态规划