GMOJ 6833. 【2020.10.24.NOIP提高A组】lover

题目大意:
LOVER解开魔法阵需要密码。密码是一种正整数有序数对(i, j),令dig (i) 表示i 十进制表示下各数位乘积,则一个数对是正确的当且仅当满足以下条件:• 0 < i, j ≤ n;• dig (i) × dig (j) > 0;• gcd (dig (i) , dig (j)) ≤ k。其中gcd (x, y) 表示正整数x, y 的最大公约数。现在恋人想知道有多少满足要求的数对。由于解锁魔法阵不需要过多的数对,你只需要输出答案对998244353 取模的值。

这是一道考场时很多大佬切了,但我不会做的题。
做法不难,主要分为三个步骤:

  • 首先,很容易可以发现,对gcd有贡献的只有2,3,5,7,所以可以设dp数组f[i][0/1][a][b][c][d]表示当前选到从后往前第i位,当前2,3,5,7的数量为a,b,c,d的数的个数,0表示没有限制的情况,1表示小于等于到i的限制的情况。
  • 求出了这个以后,就可以用高维前缀和求出数组sum[a][b][c][d]表示当前当前2,3,5,7的数量>=a,b,c,d时的数的个数。
  • 最后,就可以枚举一种符合答案的(a,b,c,d)。设数对为(i,j),分类讨论i控制某几个点和j控制某几个点的情况,共16种,复制粘贴即可。
    有一点细节要注意:如果直接确定i,j可以取得(a,b,c,d)的范围,会算重复。比如当i控制a,b,c,d的最小值,或者j控制a,b,c,d的最小值时,i和j都可以选(a,b,c,d),这样显然是有问题的。
    经过roger大佬的帮助,我学会了一种方法:考虑i的范围时,令其不能与j重复,j则可以重复,这样就不会算重了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 20
#define ll long long
#define mo 998244353
using namespace std;
ll n,k,i,j,a,b,c,d,len,lim[N],f[N][3][N*3][N*2][N][N],g[N*3][N*2][N][N],sum[N*3][N*2][N][N],ans,a1,b1,c1,d1;
ll check(ll a,ll b,ll c,ll d,ll k){
	ll i,sum=1;
	for (i=1;i<=a;i++) sum*=2;
	for (i=1;i<=b;i++) sum*=3;
	for (i=1;i<=c;i++) sum*=5;
	for (i=1;i<=d;i++) sum*=7;
	if (sum<=k) return 1;
	return 0;
}
ll get(ll al,ll ar,ll bl,ll br,ll cl,ll cr,ll dl,ll dr){
	ar++;br++;cr++;dr++;
	ll res=sum[al][bl][cl][dl];
	res=res-sum[ar][bl][cl][dl]-sum[al][br][cl][dl]-sum[al][bl][cr][dl]-sum[al][bl][cl][dr];res=(res+mo)%mo;
	res=res+sum[ar][br][cl][dl]+sum[ar][bl][cr][dl]+sum[ar][bl][cl][dr]
	+sum[al][br][cr][dl]+sum[al][br][cl][dr]+sum[al][bl][cr][dr];res%=mo;
	res=res-sum[ar][br][cr][dl]-sum[ar][br][cl][dr]-sum[ar][bl][cr][dr]-sum[al][br][cr][dr];res=(res+mo)%mo;
	res=res+sum[ar][br][cr][dr];res%=mo;
	return res;
}
int main(){
	freopen("lover.in","r",stdin);
	freopen("lover.out","w",stdout);
	scanf("%lld%lld",&n,&k);
	f[0][0][0][0][0][0]=f[0][1][0][0][0][0]=1;
	while (n){
		lim[++len]=n%10;
		n/=10;
	}
	for (i=0;i<len;i++){
		for (a=0;a<=i*3;a++)
		for (b=0;b<=i*2;b++)
		for (c=0;c<=i;c++)
		for (d=0;d<=i;d++)
			if (f[i][0][a][b][c][d]||f[i][1][a][b][c][d])
			for (j=1;j<=9;j++){
				a1=b1=c1=d1=0;
				if (j==2) a1++;else
				if (j==3) b1++;else
				if (j==4) a1+=2;else
				if (j==5) c1++;else
				if (j==6) a1++,b1++;else
				if (j==7) d1++;else
				if (j==8) a1+=3;else
				if (j==9) b1+=2;
				f[i+1][0][a+a1][b+b1][c+c1][d+d1]=(f[i+1][0][a+a1][b+b1][c+c1][d+d1]+f[i][0][a][b][c][d])%mo;
				if (j<lim[i+1]) f[i+1][1][a+a1][b+b1][c+c1][d+d1]=(f[i+1][1][a+a1][b+b1][c+c1][d+d1]+f[i][0][a][b][c][d])%mo;
				if (j==lim[i+1]) f[i+1][1][a+a1][b+b1][c+c1][d+d1]=(f[i+1][1][a+a1][b+b1][c+c1][d+d1]+f[i][1][a][b][c][d]);
			}
	}
	for (i=1;i<=len;i++)
		for (a=0;a<=i*3;a++)
		for (b=0;b<=i*2;b++)
		for (c=0;c<=i;c++)
		for (d=0;d<=i;d++){
			if (i<len)
				sum[a][b][c][d]=g[a][b][c][d]=(g[a][b][c][d]+f[i][0][a][b][c][d])%mo;
			else
				sum[a][b][c][d]=g[a][b][c][d]=(g[a][b][c][d]+f[i][1][a][b][c][d])%mo;
		}
			
	for (a=len*3;a>=0;a--)
	for (b=len*2;b>=0;b--)
	for (c=len;c>=0;c--)
	for (d=len;d>=0;d--)
		sum[a][b][c][d]=(sum[a][b][c][d]+sum[a+1][b][c][d])%mo; 
	for (a=len*3;a>=0;a--)
	for (b=len*2;b>=0;b--)
	for (c=len;c>=0;c--)
	for (d=len;d>=0;d--)
		sum[a][b][c][d]=(sum[a][b][c][d]+sum[a][b+1][c][d])%mo;
	for (a=len*3;a>=0;a--)
	for (b=len*2;b>=0;b--)
	for (c=len;c>=0;c--)
	for (d=len;d>=0;d--)
		sum[a][b][c][d]=(sum[a][b][c][d]+sum[a][b][c+1][d])%mo;
	for (a=len*3;a>=0;a--)
	for (b=len*2;b>=0;b--)
	for (c=len;c>=0;c--)
	for (d=len;d>=0;d--)
		sum[a][b][c][d]=(sum[a][b][c][d]+sum[a][b][c][d+1])%mo;
	ans=0;
	for (a=0;a<=len*3;a++)
	for (b=0;b<=len*2;b++)
	for (c=0;c<=len;c++)
	for (d=0;d<=len;d++)
		if (check(a,b,c,d,k)){
			ans=(ans+get(a+1,len*3,b+1,len*2,c+1,len,d+1,len)*g[a][b][c][d]%mo)%mo;
			
			ans=(ans+get(a,a,b+1,len*2,c+1,len,d+1,len)*get(a,len*3,b,b,c,c,d,d)%mo)%mo;
			ans=(ans+get(a+1,len*3,b,b,c+1,len,d+1,len)*get(a,a,b,len*2,c,c,d,d)%mo)%mo;
			ans=(ans+get(a+1,len*3,b+1,len*2,c,c,d+1,len)*get(a,a,b,b,c,len,d,d)%mo)%mo;
			ans=(ans+get(a+1,len*3,b+1,len*2,c+1,len,d,d)*get(a,a,b,b,c,c,d,len)%mo)%mo;
			
			ans=(ans+get(a,a,b,b,c+1,len,d+1,len)*get(a,len*3,b,len*2,c,c,d,d)%mo)%mo;
			ans=(ans+get(a,a,b+1,len*2,c,c,d+1,len)*get(a,len*3,b,b,c,len,d,d)%mo)%mo;
			ans=(ans+get(a,a,b+1,len*2,c+1,len,d,d)*get(a,len*3,b,b,c,c,d,len)%mo)%mo;
			ans=(ans+get(a+1,len*3,b,b,c,c,d+1,len)*get(a,a,b,len*2,c,len,d,d)%mo)%mo;
			ans=(ans+get(a+1,len*3,b,b,c+1,len,d,d)*get(a,a,b,len*2,c,c,d,len)%mo)%mo;
			ans=(ans+get(a+1,len*3,b+1,len*2,c,c,d,d)*get(a,a,b,b,c,len,d,len)%mo)%mo;
			
			ans=(ans+get(a,a,b,b,c,c,d+1,len)*get(a,len*3,b,len*2,c,len,d,d)%mo)%mo;
			ans=(ans+get(a,a,b,b,c+1,len,d,d)*get(a,len*3,b,len*2,c,c,d,len)%mo)%mo;
			ans=(ans+get(a,a,b+1,len*2,c,c,d,d)*get(a,len*3,b,b,c,len,d,len)%mo)%mo;
			ans=(ans+get(a+1,len*3,b,b,c,c,d,d)*get(a,a,b,len*2,c,len,d,len)%mo)%mo;
			
			ans=(ans+g[a][b][c][d]*get(a,len*3,b,len*2,c,len,d,len));
		}
	printf("%lld
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/Mohogany/p/13871341.html