scauoj 18025 小明的密码 数位DP

大兔子大兔子 提交于 2020-03-26 12:25:05

18025 小明的密码

时间限制:4000MS  内存限制:65535K
提交次数:0 通过次数:0

题型: 编程题   语言: G++;GCC

Description

小明的密码由N(1<=N<=12)个数字构成,每个数字都可以是0至9中任意一个数字,但小明的密码还有
一个特点就是密码中连续的M(1<=M<=4)个数字的和是质数,现给定M和N,求满足条件的密码共有多少
个?




输入格式

第1行是T,case数量,此后T行,每行两个数,N和M



输出格式

每个case输出一个满足条件的密码总数



输入样例

2
1 1
2 1



输出样例

4
16
 这题数据很小,可以直接DFS暴力求解,但是有更好的DP思路。。不过代码略长dp[i][j][k][z],i表示当前是几位数,j表示当前这个数的最后一位,k,z分别是倒数二、三位。 假设M=4时.如果j+k+z+a是素数的时候,dp[i-1][k][z][a]可以推出dp[i][j][k][z],也就是dp[i][j][k][z]+=dp[i-1][k][z][a]; 这样一来,我们就可以用暴力的方法求出dp[4][j][k][z],然后递推上去。时间复杂度是n*10^m 下面是代码
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <stack>
typedef long long ll;
#define X first
#define Y second
#define mp(a,b) make_pair(a,b)
#define pb push_back
#define sd(x) scanf("%d",&(x))
#define Pi acos(-1.0)
#define sf(x) scanf("%lf",&(x))
#define ss(x) scanf("%s",(x))
#define maxn 1000000
#include <ctime>  
//如果是学校的同学要把这个删掉,因为学校OJ禁了time头文件.
const int inf=0x3f3f3f3f;
const long long mod=1000000007;
using namespace std;
int dp[15][10][10][10];
long long ans[15][5];
bool prime[100];
void get_prime()
{
    prime[0]=prime[1]=1;
    for(int i=2;i<=40;i++)
    {
        if(!prime[i])
        {
            for(int j=i+i;j<=40;j+=i)
                prime[j]=1;
        }
    }
}
void init()
{
    ans[0][1]=1;
    //M=1
    for(int i=1;i<=12;i++)
        ans[i][1]=ans[i-1][1]*4;
    //M=2
    for(int i=0;i<=9;i++)
        for(int j=0;j<=9;j++)
            if(!prime[i+j])
                dp[2][0][0][i]++;
    for(int i=3;i<=12;i++)
        for(int j=0;j<=9;j++)
            for(int k=0;k<=9;k++)
                if(!prime[j+k])
                    dp[i][0][0][j]+=dp[i-1][0][0][k];
    for(int i=1;i<=12;i++)
        for(int j=0;j<=9;j++)
            ans[i][2]+=dp[i][0][0][j];

    //M=3
    memset(dp,0,sizeof dp);
    for(int i=0;i<=9;i++)
        for(int j=0;j<=9;j++)
            for(int k=0;k<=9;k++)
                if(!prime[i+j+k])
                    dp[3][0][i][j]++;
    for(int i=4;i<=12;i++)
        for(int j=0;j<=9;j++)
            for(int k=0;k<=9;k++)
                for(int z=0;z<=9;z++)
                    if(!prime[j+k+z])
                        dp[i][0][j][k]+=dp[i-1][0][k][z];
    for(int i=1;i<=12;i++)
        for(int j=0;j<=9;j++)
            for(int k=0;k<=9;k++)
                ans[i][3]+=dp[i][0][j][k];

    //M=4
    memset(dp,0,sizeof dp);
    for(int i=0;i<=9;i++)
        for(int j=0;j<=9;j++)
            for(int k=0;k<=9;k++)
                for(int z=0;z<=9;z++)
                    if(!prime[i+j+k+z])
                        dp[4][i][j][k]++;
    for(int i=5;i<=12;i++)
        for(int j=0;j<=9;j++)
            for(int k=0;k<=9;k++)
                for(int z=0;z<=9;z++)
                    for(int a=0;a<=9;a++)
                        if(!prime[j+k+z+a])
                            dp[i][j][k][z]+=dp[i-1][k][z][a];
    for(int i=1;i<=12;i++)
        for(int j=0;j<=9;j++)
            for(int k=0;k<=9;k++)
                for(int a=0;a<=9;a++)
                    ans[i][4]+=dp[i][j][k][a];
}
int main()
{
    #ifdef local
    freopen("in","r",stdin);
    //freopen("out","w",stdout);
    int _time=clock();
    #endif
    get_prime();
    init();
    int T;
    cin>>T;
    while(T--)
    {
        int n,m;
        cin>>n>>m;
        cout<<ans[n][m]<<endl;
    }
    #ifdef local
    printf("time: %d\n",int(clock()-_time));
    #endif
}
View Code