HDU6821 Set2(组合数+dp)

DP的设计最重要的是找到合理的方案,如果求的是方案,那就要要求不重不漏。

一般这种都跟组合数结合,一定要给组合数公式想到一个实际的物理意义,这样理解起来比较方便

这题我确实不会,但是看题解觉得很牛逼,也很有道理,关键就是找到一个点能使得所有状态不重不漏

一般都是考虑题目给的信息,很多情况下都是考虑集合中有什么数,然后以他为立足点,这是我的一些小思考

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pll;
const int N=2e5+10;
const int M=2e6+10;
const int inf=0x3f3f3f3f;
const ll mod=998244353;
int f[5010][5010];
int n;
int tmp[N],g[N];
int cnt[N],sum[N];
ll qmi(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1){
            res=res*a%mod;
        }
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
int C(int a,int b){
    if(a<b)
        return 0;
    return 1LL*tmp[a]*g[b]%mod*g[a-b]%mod;
}
void init(){
    int i,j;
    tmp[0]=1;
    for(int i=1;i<5000;++i) tmp[i]=1LL*tmp[i-1]*i%mod;
    g[4999]=qmi(tmp[4999],mod-2);
    for(int i=4998;i>=0;--i) g[i]=1LL*g[i+1]*(i+1)%mod;
}
int main(){
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    init();
    while(t--){
        int n,k;
        cin>>n>>k;
        int r=n%(k+1);
        int i,j;
        for(i=0;i<=n;i++){
            for(j=0;j<=n;j++){
                f[i][j]=0;
            }
        }
        f[0][0]=1;
        if(r==0){
            for(i=1;i<n;i++){
                cout<<0<<" ";
            }
            cout<<0;
            cout<<endl;
        }
        else if(n<=k){
            for(i=1;i<n;i++){
                cout<<1<<" ";
            }
            cout<<1;
            cout<<endl;
        }
        else{
            for(i=0;i<n;i++){
                for(j=0;j<=n;j++){
                    if(j+k+i-1<=n-r) f[i+1][j+k]=(f[i+1][j+k]+f[i][j])%mod;//i被当成最小数删除
                    if(j) f[i+1][j-1]=(f[i+1][j-1]+1ll*f[i][j]*j%mod)%mod;//被当作随机数删除,有j个位置可以选
                }
            }
            ll tot=0;
            for(i=1;i<=n;i++){
                int j=n-r-i+1;//还要选的数目
                sum[i]=1ll*f[i-1][j]*C(n-i,j)%mod*tmp[j]%mod;//组合数+排列
                tot=(tot+sum[i])%mod;//记录总方案数
                cnt[i]=1ll*f[i-1][j]*C(n-i-1,j)%mod*tmp[j]%mod;//当x>i时 x存留,i提供的贡献
            }
            tot=qmi(tot,mod-2);
            ll res=0;
            for(i=1;i<=n;i++){
                if(i!=n)
                    cout<<(sum[i]+res)*tot%mod<<" ";
                else
                    cout<<(sum[i]+res)*tot%mod<<endl;
                res=(res+cnt[i])%mod;
            }
        }
    }
    return 0;
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13608543.html