CF628D Magic Numbers

一、题目

点此看题

本题翻译有误,刚拿到这道题的同学一定要去看讨论区!

二、解法

能一眼看出来要写数位 d p dp dp吧,偶数位奇数位比较好处理,关键是判断能被 m m m整除,一个经典的讨论是转化成取模 m m m等于 0 0 0,设 d p [ i ] [ j ] dp[i][j] dp[i][j]未考虑到了第 i i i位,余数为 r r r的方案数,最后要求余数 = 0 =0 =0即可。

由于我们做了差分,注意要特判 l l l是不是满足要求的数。

#include <cstdio>
#include <cstring>
#define int long long
const int M = 2005;
const int MOD = 1e9+7;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,d,l,r,a[M],dp[M][M];char s[M];
int dfs(int x,int r,int up,int zero)
{
	if(!x) return !r && !zero;
	if(dp[x][r]!=-1 && !up && !zero) return dp[x][r];
	int ans=0;
	for(int i=0;i<=9;i++)
	{
		if(up && i>a[x]) break;
		if(((n-x)%2==1 && i!=d) || ((n-x)%2==0 && i==d))
			continue;
		ans=(ans+dfs(x-1,(10*r+i)%m,up&&(i==a[x]),zero&&(i==0)))%MOD;
	}
	if(!up && !zero) dp[x][r]=ans;
	return ans;
}
int work(int f)
{
	scanf("%s",s);n=strlen(s);
	for(int i=0;i<n;i++)
		a[n-i]=s[i]-'0';
	int sum=0;
	for(int i=0;i<n;i++)
	{
		int x=s[i]-'0';
		if((i+1)&1) {if(x==d) f=1;}
		else {if(x!=d) f=1;}
		sum=(sum*10+x)%m;
	}
	return dfs(n,0,1,1)-(sum==0 && f==0);
}
signed main()
{
	memset(dp,-1,sizeof dp);
	m=read();d=read();
	int l=work(0),r=work(1);
	printf("%lld\n",(r-l+MOD)%MOD);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值