牛客练习赛64 D宝石装箱(容斥定理、01背包)

宝石装箱
这个题容斥应该都很好想到,如果没有限制的话,那么一对一,答案全排列,之后减去第 i i i个箱子放错的情况,之后又得加上两个箱子放错的情况, … \dots ,那么后面这个答案如何维护呢,我们设 d p [ i ] [ j ] dp[i][j] dp[i][j]为当前到了第 i i i个箱子,此时已经放错了 j j j个的方案数,那么 f [ i ] [ j ] = f [ i − 1 ] [ j ] + f [ i − 1 ] [ j − 1 ] ∗ a [ i ] f[i][j]=f[i-1][j]+f[i-1][j-1]*a[i] f[i][j]=f[i1][j]+f[i1][j1]a[i]
,考虑用一维优化下,二维容易爆空间,得到 d p [ 1 ] , d p [ 2 ] , … dp[1],dp[2], \dots dp[1],dp[2],然后把之后的每种方案对应乘上其他宝石的全排列即可,最后就是容斥下得到答案。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define rush() int T;scanf("%d",&T);while(T--)
#define mm(a,b) memset(a,b,sizeof(a))
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define sc(a) scanf("%d",&a)
#define sc2(a,b) scanf("%d%d",&a,&b)
#define pf(a) printf("%d\n",a)
#define pf2(a,b) printf("%d %d\n",a,b)
#define p_f(a) printf("%d ",a)
#define pyn(a) if(a)puts("Yes");else puts("No");
#define fi first
#define se second
#define db double
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;
const db eps=1e-9;
const int N=8e3+5;
const int P=998244353;
int n,x,a[N];
ll dp[N],fac[N];
int32_t main()
{
    
    
    cin>>n;
    fac[0]=fac[1]=1ll;
    for(int i=2;i<=n;i++)fac[i]=(i*fac[i-1])%P;
    ll ans=fac[n];
    for(int i=1;i<=n;a[x]++,i++)cin>>x;
    dp[0]=1;
    for(int i=1;i<=n;i++)for(int j=i;j>=1;j--)dp[j]=(dp[j]+a[i]*dp[j-1])%P;
    for(int i=1;i<=n;i++)ans=i&1?(ans-dp[i]*fac[n-i]%P+P)%P:(ans+dp[i]*fac[n-i]%P)%P;
    return cout<<ans,0;
}

猜你喜欢

转载自blog.csdn.net/zhouzi2018/article/details/106300443