J - Junior Mathematician(数位dp)

传送门

x x x在十进制数下有 k k k位,且 d ( x , i ) d(x,i) d(x,i)表示 x x x的第 i i i

定义 f ( x ) = ∑ i = 1 k − 1 ∑ j = i + 1 k d ( x , i ) ∗ d ( x , j ) f(x)=\sum\limits_{i=1}^{k-1}\sum\limits_{j=i+1}^kd(x,i)*d(x,j) f(x)=i=1k1j=i+1kd(x,i)d(x,j)

求在 [ L , R ] [L,R] [L,R]内满足 x = = f ( x ) % m x==f(x)\%m x==f(x)%m的个数


考虑数位 d p dp dp从高到低枚举每一个位置

定义 f [ i ] [ j ] [ q ] [ w ] f[i][j][q][w] f[i][j][q][w]为枚举到第 i i i位,前缀大小为 j j j,当前贡献为 q q q,当前数字为 w w w的方案数

考虑前 i − 1 i-1 i1位前缀为 s u m sum sum,贡献为 r e s res res,数字为 l a s t last last

那么第 i i i位为 x x x,当前位权值为 l i li li

前缀为 ( s u m + x ) % m (sum+x)\%m (sum+x)%m,贡献变为 ( r e s + x ∗ s u m ) % m (res+x*sum)\%m (res+xsum)%m,当前数字变为 ( l a s t + x ∗ l i ) % m (last+x*li)\%m (last+xli)%m

这样时间空间复杂度都是 O ( n m 3 ) = 300000 ∗ 3600 O(nm^3)=300000*3600 O(nm3)=3000003600

但是可以直接维护 f ( x ) − x f(x)-x f(x)x的值,因为我们只需要判断相等就好了

那么定义 f [ i ] [ j ] [ q ] f[i][j][q] f[i][j][q]为枚举到第 i i i位,前缀为 j j j, f ( x ) − x f(x)-x f(x)x q q q的方案

设下一位填 x x x

那么前缀变为 x + j x+j x+j, f ( x ) − x f(x)-x f(x)x变为 q + x ∗ j − x ∗ 1 0 i q+x*j-x*10^i q+xjx10i

这题卡常太难受了…

#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
int n,m,bit[5009],dig[5009],f[5009][61][61][2],id,ok[5009][61][61][2];
char a[5009],b[5009];
int dfs(int num,int pre,int fx,int limit)
{
	long long ans = 0;
	if( num==0 )	return fx==0;
	if( ok[num][pre][fx][limit]==id )	return f[num][pre][fx][limit];
	ok[num][pre][fx][limit] = id;
	int lim = limit?dig[num]:9;
	for(int i=0;i<=lim;i++)
	{
		int he = ((fx+i*pre-i*bit[num])%m+m)%m;
		ans = ans+dfs(num-1,(pre+i)%m,he,limit&&(i==dig[num]) );
	}
	ans = ( ans+mod )%mod;
	f[num][pre][fx][limit] = ans;
	return ans;
}
int solve( char a[] )
{
	++id;
	int n = strlen( a+1 );
	for(int i=1;i<=n;i++)	dig[i] = a[n-i+1]-'0';
	return dfs(n,0,0,1);	
}
int main()
{
	int t; cin >> t;
	while( t-- )
	{
		scanf("%s%s%d",a+1,b+1,&m);
		int n = strlen( a+1 ),n2 = strlen( b+1 );
		a[n]--;
		for(int i=n;i>=1;i--)
		{
			if( a[i]>='0'&&a[i]<='9' )	break;
			a[i] = '9', a[i-1]--;
		}
		bit[1] = 1;
		for(int i=2;i<=n2;i++)	bit[i] = bit[i-1]*10%m;
		cout << ( solve(b) - solve(a) + mod )%mod << endl;
	}
} 
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: Age of Ai 设计师:meimeiellie 返回首页