• [10.18模拟赛] 序列 (DP)


    [10.18模拟赛] 序列

    题目描述

    山山有一个整数序列s1,s2,…,sn,其中1≤si≤k。

    求出有多少个准确移除m个元素后不同的序列。答案模(1e9+7)

    输入

    输入包括几个测试用例,并且由文件结束终止。

    每一个测试用例的第一行包含整数n,m和k。

    第二行包含n个整数,即s1,s2,…,sn。

    输出

    对于每一个测试用例,输出一个表示结果的整数。

    样例输入

    3 2 2
    1 2 1
    4 2 2
    1 2 1 2

    样例输出

    2
    4

    提示

    (1 ≤ n ≤ 10^5;1 ≤ m ≤ min{n - 1, 10}; 1 ≤ k ≤ 10; 1 ≤ si ≤ k;)

    n的总和不超过(10^6.)

    Solution

    其实这是牛客网暑假集训的题目

    官方题解写的太飘逸~如下

    预处理 Next[i][c]表示 i 之后第一个字符 c 的位置
    dp[i][j]表示当时匹配到 i,删了 j 个,不同的方案数
    转移时枚举下一个字符 c,转移到 dp[next[i][c],j+next[i][c]-i]
    

    下面来讲一下蒟蒻我的理解,首先如果不考考虑删除重复元素的情况,那这道题其实还是比较水的,就是一个dp,设dp[i][j]为前i个元素删除了j个方案数

    [dp[i][j]=dp[i-1][j-1]+dp[i-1][j] ]

    这个方程还是挺好理解的吧,这道题就建立在这个方程之上

    我们看这样一个序列{...,4,3,1,4,5},如果删除中间3,1,4}三个元素,集合会变成这样{...4,3,1,4,5},同样如果删除前面{4,3,1}三个元素,集合变成了这样{...4,3,1,4,5},可以看到同样的集合我们算了两遍

    那么怎么减去多余的部分呢?

    我们记录一下每个元素x上一次出现的位置(pre[x]),出现的前一段{...}我们都是会重复计算的,所以要减去(dp[pre[x]-1][j-i+pre[x]])

    Code

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define Min(a,b) (a)<(b)?(a):(b)
    #define Max(a,b) (a)>(b)?(a):(b)
    #define lol long long
    #define in(i) (i=read())
    using namespace std;
    
    const int N = 1e5+10, M=20 , mod=1e9+7;
    
    int read() {
    	int ans=0,f=1; char i=getchar();
    	while(i<'0' || i>'9') {if(i=='-') f=-1; i=getchar();}
    	while(i>='0' && i<='9') ans=(ans<<1)+(ans<<3)+i-'0',i=getchar();
    	return ans*=f;
    }
    
    int n,m,k;
    int dp[N][M],pre[M];
    
    int main()
    {
        //freopen("removal.in" , "r" , stdin);
        //freopen("removal.out" , "w" , stdout);
        while(scanf("%d%d%d",&n , &m , &k)!=EOF) {
            memset(dp , 0 , sizeof(dp));
            memset(pre , 0 , sizeof(pre));
            for(int i = 0 ; i <= n ; i++) dp[i][0] = 1;
            for(int i = 1 , x ; i <= n ; i++) {
                in(x);
                for(int j = 1 ; j <= (Min(i , m)) ; j++) {
                    dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j])%mod;
                    if( pre[x] && (j >= i - pre[x]) )
                        (dp[i][j] -= dp[pre[x] - 1][j- i + pre[x]])%=mod;
                }pre[x] = i;
            }printf("%d
    ",(dp[n][m]+mod)%mod);
        }
    }
    
  • 相关阅读:
    自己做一个无敌的文件粉碎机
    编程王道,唯“慢”不破
    在Flex4中嵌入字体
    java函数参数默认值
    Adobe Air移动开发本人体会
    安装VS2013,可是电脑C盘没空间了,今天早上整理了下
    SilverFoxServer出炉!!
    C#中Abstract和Virtual
    解决insert语句插入时,需要写列值的问题
    SQL 标量函数-----日期函数 day() 、month()、year()
  • 原文地址:https://www.cnblogs.com/real-l/p/9811421.html
Copyright © 2020-2023  润新知