CF628D. Magic Numbers(数位DP)

题目链接:https://vjudge.net/contest/372594#problem/B
题意:给出m和d,a和b,找出a到b之间的所有偶数位为d,所有奇数位不为d的数,且要求这个数为m的倍数
解题思路:
①注意a和b长度可能达到2000,用字符串保存
②利用dp[pos][mmod]表示pos位置处余数为mmod的数的个数,在进行数位dp过程中注意前缀0情况和有上限情况。

下面是我自己写的代码,但不明白为什么超时了

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;
const int mod=1e9+7;
#define ll long long
int n,m;
int t=0;
int dp[2100][2100];
int num[2100];
char a[2200],b[2200];
//flag表示奇偶数 pre表示前缀0情况 mmod表示取余m后的余数
int solve(int pos,int len,int limit,int mmod,int flag,int pre)
{
	if(pos<0)
		return mmod==0;
	if(!limit&&dp[pos][mmod])
		return dp[pos][mmod];
	int up=limit?num[pos]:9;
	int ans=0;
	for(int i=0;i<=up;i++){
		if(flag==0&&i==n)  continue;
		if(flag==1&&i!=n)  continue;
		if(pre==0&&i==0)
			ans+=solve(pos-1,len,limit&&i==up,(mmod*10+i)%m,flag^1,0);
		else
		    ans+=solve(pos-1,len,limit&&i==up,(mmod*10+i)%m,flag^1,1);
		ans%=mod;
	}
	if(!limit)
		dp[pos][mmod]=ans;
	return ans;
}
void helper(int len)
{
	for(int i=0;i<len;i++)
		if(num[i]){
			num[i]--;
			break;
		}
		else
			num[i]=9;
}
int cal(char* s)
{
	int len=strlen(s);
	for(int i=len-1;i>=0;i--)
	{
		num[len-1-i]=s[i]-'0';
	}
	if(!t)
		helper(len),t++;
	return solve(len-1,len,1,0,0,0);
}
int main()
{
	scanf("%d%d",&m,&n);
	scanf("%s",a); scanf("%s",b);
	int ans1=cal(a);
	int ans2=cal(b);
	printf("%d\n",(ans2-ans1+mod)%mod);
	return 0;
}

这个是我看到的ac的代码(不是我自己写的,我转载别人的)

#include<iostream>
#include<cstdio>
#include<string>
using namespace std;

using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int n = 2020;

char a[n], b[n];
int m, n;
int dg[n];
ll f[n][n];

inline ll add(ll x, ll y) {
    x = x + y;
    return x >= mod ? x-mod : x;
}

ll dfs(int i, int s, bool flag, bool e) {  // dp[i][s] , flag 表示奇数还是偶数,e代表边界
    if(i == -1) return s == 0;
    if(!e && ~f[i][s]) return f[i][s];
    ll res = 0ll;
    int u = e ? dg[i] : 9;
    for(int d = 0; d <= u; ++d) {
        if(flag == 1 && d == n) continue;
        if(flag == 0 && d != n) continue;
        res = add(res, dfs(i-1, (s*10+d)%m, flag^1, e && d==u));
    }
    return e ? res : f[i][s] = res;
}

void deal(int& len) {
    for(int i = 0; i < len; ++i) {
        if(dg[i] == 0) dg[i] = 9;
        else {
            --dg[i];
            break;
        }
    }
    return ;
}

ll solve(char c[], bool fg) {
    int len = strlen(c);
    for(int i = 0; i < len; ++i) dg[i] = c[len-1-i] - '0';
    if(fg) deal(len);
    return dfs(len-1, 0, 1, 1);
}

int main()
{
    scanf("%d %d", &m, &n);
    scanf("%s %s", a, b);
    memset(f, -1, sizeof f);
    printf("%i64d\n", add(solve(b, 0) - solve(a, 1), mod));
    return 0;
}
原创文章 65 获赞 3 访问量 2080

猜你喜欢

转载自blog.csdn.net/littlegoldgold/article/details/106039400