决战

解法1:DP+常数优化

f[i][S][j]表示i列,第i列状态为S,放了j个哲学家

第一维可以滚动

f[i][S][j]+=f[i-1][S'][l]

对于S和S'只枚举合法的,这可以预处理出来

然后枚举j时可以算出上下界

解法2:

矩阵+NTT优化DP

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 typedef long long lol;
 8 lol f[2][8][7501],Mod=998244353,ans;
 9 int n,m,pw[4],v[8],mp[8][8],num[8],s[8][8],pre,nxt;
10 int main()
11 {
12     int i,j,k,l;
13     cin>>n>>m;
14     pw[1]=1;pw[2]=2;pw[3]=4;
15     num[0]=0;num[1]=1;num[2]=1;num[3]=2;num[4]=1;num[5]=2;num[6]=2;num[7]=3;
16     for (i=1; i<=3; i++)
17         for (j=1; j<=3; j++)
18             scanf("%d",&s[i][j]);
19     for (i=0; i<=7; i++)
20     {
21         v[i]=1;
22         int tmp[5]= {0};
23         for (j=1; j<=3; j++)
24             if (i&pw[j])
25             {
26                 tmp[j-1]|=s[2][1];
27                 tmp[j+1]|=s[2][3];
28             }
29         for (j=1; j<=3; j++)
30             if ((i&pw[j])&&tmp[j]) v[i]=0;
31     }
32     for (i=0; i<=7; i++)
33         if (v[i])
34         {
35             for (j=0; j<=7; j++)
36                 if (v[j])
37                 {
38                     int tmp1[5]= {0},tmp2[5]= {0};
39                     mp[i][j]=1;
40                     for (k=1; k<=3; k++)
41                         if (pw[k]&i)
42                         {
43                             tmp1[k-1]|=s[3][1];
44                             tmp1[k+1]|=s[3][3];
45                             tmp1[k]|=s[3][2];
46                         }
47                     for (k=1; k<=3; k++)
48                         if (pw[k]&j)
49                         {
50                             tmp2[k-1]|=s[1][1];
51                             tmp2[k+1]|=s[1][3];
52                             tmp2[k]|=s[1][2];
53                         }
54                     for (k=1; k<=3; k++)
55                         if (tmp2[k]&&(i&pw[k])||tmp1[k]&&(j&pw[k]))
56                             mp[i][j]=0;
57                 }
58         }
59     pre=0;nxt=1;
60     for (i=0; i<=7; i++)
61         f[pre][i][num[i]]=v[i];
62     for (i=2; i<=n; i++)
63     {
64         int a=min(i*3,m),b=max(0,m-(n-i+1)*3);
65         for (j=0; j<=7; j++)
66             if (v[j])
67             {
68                 for (k=0; k<=7; k++)
69                     if (v[k]&&mp[j][k])
70                     {
71                         for (l=b; l<=a-num[k]; l++)
72                         {
73                             f[nxt][k][l+num[k]]+=f[pre][j][l];
74                             if (f[nxt][k][l+num[k]]>=Mod)
75                             f[nxt][k][l+num[k]]-=Mod;
76                         }
77                     }
78             }
79         for(j=0; j<=7; j++)
80             if(v[j])
81                 for(k=b; k<=a; k++)f[pre][j][k]=0;
82         swap(nxt,pre);
83     }
84     for (i=0; i<=7; i++)
85         ans=ans+f[pre][i][m],ans%=Mod;
86     cout<<ans;
87 }

 

转载于:https://www.cnblogs.com/Y-E-T-I/p/8696333.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值