CSP-S2 Emiya 家今天的饭

题目描述

在这里插入图片描述
在这里插入图片描述

题目分析

  • 这一道题本身算法并不难,但思考难度也不低。
  • “烹饪方法互不相同”这个条件用DP可以很好解决,关键是每一个食材出现次数不超过 k 2 \frac{k}{2} 接下来我们所说的不合法均指不满足该条件
  • 本题最关键的一点便是——容斥。考虑先求出总的方案数,再减去不合法的方案数。
  • 总数求法很简单,那么如何求不合法的方案数呢?我们考虑先枚举超出限制的食材。因为超限的食材会出现超过 k 2 \frac{k}{2} 次,所以不可能同时有两个食材超出限制,这是解决这个问题的突破口。
  • 接着我们就可以设DP了,朴素的做法是设 f [ i ] [ j ] [ k ] f[i][j][k] 表示当前DP做到第 i i 种烹饪方法,有 j j 道菜不用食材 x x k k 道菜用了食材 x x ,这样的情况有多少种方案。其中食材 x x 指的是我们所枚举的超限的食材。
  • 这样的话我们的答案就是满足 j < k j<k f [ n ] [ j ] [ k ] f[n][j][k] 的和。
  • 但我们发现这样子做的时间复杂度是 O ( m n 3 ) O(m*n^3) 的,那么该如何优化呢?
  • 发现这个DP的关键是 j < k j<k ,移项可得 j k < 0 j-k<0 ,假如我们把 j k j-k 当成状态,是否能优化DP呢?
  • 答案是肯定的。
  • 我们设 f [ i ] [ p ] f[i][p] ,其中 i i 的意义同上, p p 就是上述的 j k j-k
  • 下面是状态转移方程:
  • f [ i ] [ p ] = { f [ i 1 ] [ p + 1 ] ( S u m a [ i ] [ x ] ) x f [ i 1 ] [ p 1 ] a [ i ] [ x ] x f [ i 1 ] [ p ] f[i][p]=\begin{cases} f[i-1][p+1]*(Sum-a[i][x])&选用食材x \\f[i-1][p-1]*a[i][x]&不选用食材x \\f[i-1][p]&不用该烹饪方法做菜 \end{cases}
  • 最后只要对于 p < 0 p<0 f [ n ] [ p ] f[n][p] 加起来即可,时间复杂度 O ( m n 2 ) O(m*n^2)

代码

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=110,M=2e3+100;
const int mod=998244353;
int a[N][M],f[N][N],Sum[N],g[N][2*N];
int main()
{
	freopen("meal.in","r",stdin);
	freopen("meal.out","w",stdout);
	int n,m;
	scanf("%d%d",&n,&m);
	memset(Sum,0,sizeof(Sum));
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++){
			scanf("%d",&a[i][j]);
			Sum[i]=(Sum[i]+a[i][j])%mod;
		}
	f[0][0]=1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			f[i][j]=(f[i-1][j]+(ll)f[i-1][j-1]*Sum[i])%mod;
		}
		f[i][0]=1;
	}
	int Ans=0;
	for(int i=1;i<=n;i++) Ans=(Ans+f[n][i])%mod;
	for(int i=1;i<=m;i++){
		memset(g,0,sizeof(g));
		g[0][n]=1;
		for(int j=1;j<=n;j++){
			for(int k=0;k<=2*n;k++){
				if(g[j-1][k]){
					g[j][k+1]=(g[j][k+1]+(ll)g[j-1][k]*(Sum[j]-a[j][i]+mod))%mod;
					g[j][k-1]=(g[j][k-1]+(ll)g[j-1][k]*a[j][i])%mod;
					g[j][k]=(g[j][k]+g[j-1][k])%mod;
				}
			}
		}
		int sum=0;
		for(int j=0;j<n;j++) sum=(sum+g[n][j])%mod;
		Ans=(Ans-sum+mod)%mod;
	}
	printf("%d\n",Ans);
	return 0;
}
发布了58 篇原创文章 · 获赞 12 · 访问量 8541

猜你喜欢

转载自blog.csdn.net/fengqiyuka/article/details/103321861