• CSUST 4002-你真的会字符串吗?(DP)


    题目链接:http://acm.csust.edu.cn/problem/4002
    CSDN食用链接:https://blog.csdn.net/qq_43906000/article/details/107803402

    Description

    对于一个正整数S,我们可以看成 (S = {s_n,s_{n-1},......,s_i,......s_1}),其中(s_i = lfloor frac S {10^{i-1}} floor mod 10)
    我们定义两个整数的#运算:(S # T={(s_n*t_n+pre_n)mod 10...,(s_1*t_1+pre_1)mod 10})
    其中(pre_i=left{egin{matrix} 0 & i=1\ (s_{i-1}*t_{i-1}+pre_{i-1})/10 & 1leq ileq n end{matrix} ight.)

    如果你了解过两个整数的加法,#运算与加法类似,不过每一位相加变成了每一相乘,并且最后的结果只保留后n位
    例如:(123 # 23 =49,258 # 24 = 132,423 # 523=49)
    现在,你有一个长度为n的整数AA,你能否求出存在多少种长度为n的正整数BB,满足(A # B = A),结果对(998244353)取模.

    PS: (A)(B)都可能存在前导零

    Input
    第一行一个整数(n(1leq n leq 2e5)),表示正整数的长度

    第二行一个长度为n的正整数(A),表示所给的正整数

    Output
    一行一个整数,表示结果.

    Sample Input 1
    2
    13
    Sample Output 1
    1

    Sample Input 2
    3
    205
    Sample Output 2
    20

    Sample Input 3
    4
    3217
    Sample Output 3
    2

    emmm,这题是个DP,维数也知道是个2维的。。。但一直不知道(dp[i][j])表示的是什么,后面被大佬一提醒。。。(j)可以表示进位的位数!哦!恍然大悟,然后劈里啪啦一顿乱敲。

    我们可以用(dp[i][j])表示为第(i)位给第(i+1)位进了(j)位的时候的方案数,那么对于第一位进行的初始化如下:

    for (int i=0; i<=9; i++) {
    	if (i*s[1]%10==s[1]) dp[1][i*s[1]/10]++;
    }
    

    然后从第二位开始进行转移,那么怎么转移呢?对于位置肯定是要枚举的,对于当前位置要放什么数(如上所写)似乎也不能避免枚举,那么现在能够进行DP吗?似乎不太行,因为我们不知道上一位的进位是多少,那么就没办法转移,所以我们还要对上一位的进位进行枚举。那么就可以得到如下方程:

    for (int i=2; i<=n; i++)
    	for (int j=0; j<=9; j++)//枚举当前放置的数
    		for (int k=0; k<=9; k++)//枚举上一位的进位
    			/*DP*/
    

    DP的话一定是在方案合理的情况下生成的,也就是说((s[i]*j+k)\%10)必须还是(s[i]),那么似乎转移也就出来了:(dp[i][(s[i]*j+k)/10]=(dp[i][(s[i]*j+k)/10]+dp[i-1][k])\%mod)
    那么最后的答案好像就是(dp[n][0])了,不过。。。显然不太对,最高位实际上进多少位都没关系,反正不参与计算的,所以最后的答案是(sum_{i=0}^{9}dp[n][i])

    不过需要注意的是,出题人提醒了一下前导零。。。。不提醒还好,一提醒我就把前导零删了。。。前导零是不能删的!!!也就是说0013得出的结果是100

    以下是AC代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int mac=2e5+10;
    const int mod=998244353;
    
    char ss[mac];
    int s[mac];
    ll dp[mac][10];
    
    int main(int argc, char const *argv[])
    {
    	int n;
    	scanf ("%d",&n);
    	scanf ("%s",ss+1);
    	for (int i=1; i<=n; i++) s[i]=ss[n-i+1]-'0';
    	for (int i=0; i<=9; i++){
    		if (i*s[1]%10==s[1]) dp[1][i*s[1]/10]++;
    	}
    	for (int i=2; i<=n; i++)
    		for (int j=0; j<=9; j++)//枚举当前放置的数
    			for (int k=0; k<=9; k++)//枚举上一位的进位
    				if ((s[i]*j+k)%10==s[i]) 
    					dp[i][(s[i]*j+k)/10]=(dp[i][(s[i]*j+k)/10]+dp[i-1][k])%mod; 
    	ll ans=0;
    	for (int i=0; i<=9; i++) ans=(ans+dp[n][i])%mod;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    路漫漫兮
  • 相关阅读:
    python set
    python中%d %2d %02d %-2d% %.2d的区别
    python dict(字典)
    python 300本电子书合集
    python tuple元组
    python end用法
    python 找出第二大值
    GPU大百科全书 第二章 凝固生命的光栅化
    GPU大百科全书 第一章:美女 方程与几何
    Notepad++中调试用心lua程序
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13437112.html
Copyright © 2020-2023  润新知