zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试]:抛硬币(DP)

    题目背景

    小$A$和小$B$是一对好朋友,他们经常一起愉快的玩耍。最近小$B$沉迷于**师手游,天天刷本,根本无心搞学习。
    但是小$B$已经入坑了几个月,却一次都没有抽到$SSR$,让他非常怀疑人生。
    勤勉的小$A$为了劝说小$B$早日脱坑,认真学习,决定以抛硬币的形式让小$B$明白他是一个彻彻底底的非洲人,从而对这个游戏绝望。


    题目传送门(内部题43)


    输入格式

    一行一个字符串$S$,字符集为所有小写字母。第二行一个数$L$如题意。


    输出格式

    一行一个数,表示本质不同的长度为$L$的子序列个数,答案对$998244353$取模。


    样例

    样例输入:

    addeade
    3

    样例输出:

    19


    数据范围与提示

    我们定义$|S|$为串$S$的长度。
    对于$10\%$的数据,$S$只由一种字符构成。
    对于另$40\%$的数据,满足$|S|,Lleqslant 15$。
    对于另$20\%$的数据,满足$|S|,Lleqslant 100$。
    对于全部$100\%$的数据,满足$|S|,Lleqslant 3,000$。


    题解

    题看起来有点虎人,但是仔细一想并不难。

    依然考虑$DP$。

    设$dp[i][j]$表示处理完$S$的前$i$为,长度为$j$的本质不同的子序列的个数。

    如果不考虑本质不同,那么转移将是$dp[i][j]=dp[i-1][j]+dp[i-1][j-1]$。

    现在来考虑减去重复的部分。

    设当前位$i$的字符为$s_i$,$s_i$的上一次出现的位置是$p$,那么以$s_p$结尾的串与算重的串一一对应。

    那么我们就需要减去$dp[p-1][j-1]$。

    于是,最终的状态转移方程是:$dp[i][j]=dp[i-1][j]+dp[i-1][j-1]-dp[p-1][j-1]$。

    时间复杂度:$Theta({|S|}^2)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    char ch[3001];
    int S[3001],L;
    int pre[3001];
    long long dp[3001][3001];
    int main()
    {
    	scanf("%s%d",ch+1,&L);
    	S[0]=strlen(ch+1);
    	for(int i=1;i<=S[0];i++)
    		S[i]=ch[i]-'a'+1;
    	for(int i=1;i<=S[0];i++)
    		for(int j=i-1;j;j--)
    			if(S[i]==S[j]){pre[i]=j;break;}
    	dp[0][0]=1;
    	for(int i=1;i<=S[0];i++)
    	{
    		dp[i][0]=1;
    		for(int j=1;j<=min(i,L);j++)
    			dp[i][j]=(dp[i-1][j]+dp[i-1][j-1]-(pre[i]?dp[pre[i]-1][j-1]:0)+998244353)%998244353;
    	}
    	printf("%lld",dp[S[0]][L]);
    	return 0;
    }
    

    rp++

  • 相关阅读:
    python 匿名函数lambda()
    python列表推导式
    python数组的基本操作一(添加,扩展,插入)
    Python的数字类型
    Python初识以及Windows安装教程
    字典简单使用
    two sum(LeetCode)
    python读写文件
    C++ volatile关键字(转)
    实验一
  • 原文地址:https://www.cnblogs.com/wzc521/p/11524399.html
Copyright © 2011-2022 走看看