[NOIp2019] Emiya家今天的饭
Description
不会让大家饿肚子,所以将做至少一道菜,即 希望品尝不同烹饪方法做出的菜,因此她要求每道菜的烹饪方法互不相同 不希望品尝太多同一食材做出的菜,因此他要求每种主要食材至多在一半的菜(即 道菜)中被使用
这里的
这些要求难不倒
Input
第
第
Output
仅一行一个整数,表示所求方案数对
Sample Input1
2 3
1 0 1
0 1 1
Sample Output1
3
由于在这个样例中,对于每组
符合要求的方案包括:
- 做一道用烹饪方法
、主要食材 的菜和一道用烹饪方法 、主要食材 的菜 - 做一道用烹饪方法
、主要食材 的菜和一道用烹饪方法 、主要食材 的菜 - 做一道用烹饪方法
、主要食材 的菜和一道用烹饪方法 、主要食材 的菜
因此输出结果为
Sample Input2
3 3
1 2 3
4 5 0
6 0 0
Sample Output2
190
做
做
因此符合要求的方案数为
Sample Input3
5 5
1 0 0 1 1
0 1 0 1 0
1 1 1 1 0
1 0 1 0 1
0 1 1 0 1
Sample Output3
742
Hint
对于所有测试点,保证
题解
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
const int MOD=998244353;
const int N=150,M=2500;
int n,m,a[N][M],l[M];//l[]记录每一列选了多少个
typedef long long ll;
ll Ans;
void Dfs(int id,int _n,ll _c,int Max)
{//当前枚举到第id行,选了_n个,方案数为_c,选的最多的列的所选个数为Max
if(id>n) return;
if(Max>n/2) return;//不符合要求
Dfs(id+1,_n,_c,Max);
int t1,t2; ll t3;
for(int i=1;i<=m;++i)
if(a[id][i])
{
++l[i],
t1=_n+1,//选
t2=max(Max,l[i]),//选
t3=_c*a[id][i]%MOD;//选
if(t2<=(t1/2)) Ans=(Ans+t3)%MOD;//符合要求
Dfs(id+1,t1,t3,t2);
--l[i];//回溯
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j) scanf("%d",&a[i][j]);
Dfs(1,0,1,0),
cout<<Ans<<endl;
return 0;
}
下面的方法来自题解【luogu5664 Emiya 家今天的饭】
先把总数符合每道菜的烹饪方法互不相同的总方案求出来,再用
考虑我们需要的限制条件
就得到了如下的状态转移方程
f[j][k]=(f[j][k]+f[j-1][k]*(cnt[j]-w[j][i]))%P;//不选当前列
f[j][k+1]=(f[j][k+1]+f[j-1][k])%P;//不选当前行
f[j][k+2]=(f[j][k+2]+f[j-1][k]*w[j][i])%P;//选当前行当前列对应的节点
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll;
const ll MOD=998244353;
const int N=250,M=2000;
int n,n2,m;
ll a[N][M],sa[N],Ans,f[N][N];
void Read()
{
Ans=1;
scanf("%d%d",&n,&m);
n2=n<<1;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
cin>>a[i][j];
sa[i]=(sa[i]+a[i][j])%MOD;
}
Ans=(Ans*(sa[i]+1))%MOD;//计算全部答案,注意不选也是一种情况
}
Ans=(Ans-1+MOD)%MOD;//减去全部不选的情况
}
void DP()
{
for(int i=1;i<=m;++i)
{
for(int j=0;j<=n2;++j)
for(int k=0;k<=n2;++k) f[j][k]=0;
f[0][0]=1;//DP初值
for(int j=1,YH=0;j<=n;++j,YH+=2)
for(int k=0;k<=YH;++k)
{
f[j][k]=(f[j][k]+f[j-1][k]*(sa[j]-a[j][i]+MOD)%MOD)%MOD,
f[j][k+1]=(f[j][k+1]+f[j-1][k])%MOD,
f[j][k+2]=(f[j][k+2]+f[j-1][k]*a[j][i]%MOD)%MOD;
}
for(int j=n+1;j<=n2;++j)
Ans=(Ans-f[n][j]+MOD)%MOD;//减去当前枚举到的不合法方案
}
}
int main()
{
Read(),DP(),cout<<Ans<<endl;
return 0;
}
本文作者:OItby @ https://www.cnblogs.com/hihocoder/
未经允许,请勿转载。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥