• 2018牛客暑假多校一 E(dp)


    题目描述:

        给你一个长度为n的数列(n<=1e5),数列只会有k(1<=k<=10)种数字。问你如果你可以在这个数列种删除m个数(max(m)=10),问你可以获得的不同的数列的个数为多少。

    题目分析:

        可以分析,因为在一个长度为n的数列种,删除m个数,倘若只让我们求方案数,那么我们直接可以运用dp[i][j],使得dp代表前i个的数列中删除j个数所形成的方案数,并列出转移方程,dp[i][j]=dp[i-1][j]+dp[i-1][j-1];

        但是,因为这个题目中是要统计不相同的数列的个数,而因为倘若前面有与a[i]相同的数字a[k] (k<i),并且i与k的位置距离小于等于j,那么就会产生重复。因此,我们之前所求出的方案数是有很多重复的。

        因此,我们还需要去判断当前的数字a[i]在前面是否出现过,倘若在之前出现过a[k],且两者之间的距离正好小于等于可以删除的个数,则我们需要减去这部分重复的方案数。此时的转移方程为 dp[i][j]=dp[i][j]-dp[pre[i]-1][j-(i-pre[i])];

    #include <bits/stdc++.h>
    #define maxn 100005
    using namespace std;
    typedef long long ll;
    const int mod=1e9+7;
    ll a[maxn];
    ll dp[maxn][20];
    int pre[maxn];
    int id[maxn];
    int main()
    {
        int n,m,k;
        while(~scanf("%d%d%d",&n,&m,&k)){
            memset(pre,0,sizeof(pre));
            memset(id,0,sizeof(id));
            for(int i=1;i<=n;i++){
                scanf("%d",&a[i]);
                pre[i]=id[a[i]];
                id[a[i]]=i;
            }
            for(int i=0;i<=m;i++){
                dp[i][i]=1;
            }
            for(int i=1;i<=n;i++){
                dp[i][0]=1;
                int d=i-pre[i];
                for(int j=1;j<=m;j++){
                    if(j>i) break;
                    dp[i][j]=((dp[i-1][j]+dp[i-1][j-1])%mod+mod)%mod;
                    if(pre[i]!=0&&d<=j){
                        dp[i][j]=((dp[i][j]-dp[pre[i]-1][j-d])%mod+mod)%mod;
                    }
                }
            }
            cout<<dp[n][m]<<endl;
        }
    }
    
  • 相关阅读:
    【codeforces 723F】stSpanning Tree
    struts2.0中struts.xml配置文件详解
    存储过程中调用JAVA程序段
    本不该逃避
    利用js实现对页面的自动刷新
    [转]从硬盘安装 RedHat Enterprise Linux Server 5 iso
    正则表达式使用
    利用XmlBean轻松读写xml(转)
    Struts2+Spring2+Hibernate3 web应用示例(七)
    在DWR中实现直接获取一个JAVA类的返回值的两种方法
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/11007267.html
Copyright © 2020-2023  润新知