6831. 2020.10.24【NOIP提高A组】T1.lover

表了一下,发现(dig)有值的数大概只有几万个,可以考虑做做。
然后发现它要(gcd<=K),考虑分解质因数后(DP)。然后不会。

考虑(DP),显然对答案有贡献的数位可以拆分成质因子。
(f[x][0/1][a][b][c][d])表示当前到了第(x)位,是否有顶格,(gcd)(2^a*3^b*5^c*7^d)的方案数。
显然可以用数位(DP)转移,转移不讲。

(g[a][b][c][d])表示(f[0][a][b][c][d]+f[1][a][b][c][d])
我们发现可以通过高维前缀和然后容斥来解决问题。
(g)为后缀和后的(g),设(h)为两两间(gcd)(2^a*3^b*5^c*7^d)的方案数。
(Solution 1)
(h[a][b][c][d])显然可以用容斥来解决。
(h[a][b][c][d]=g[a][b][c][d]^2-g[a+1][b][c][d]^2-g[a][b+1][c][d]^2-g[a][b][c+1][d]^2-g[a][b][c][d+1]^2+......)
当然这种写法十分的麻烦(吧)

(Solution 2)
高维前缀和以后,设(p[a][b][c][d])表示(h)的后缀和
那么可以惊奇地发现:(p)=(g*g)!!!
是的,就是这么的神奇,求出(p)以后在逆推回去就得到(h)了。
答案就是把所有(<=gcd)的方案数加起来。。。

(Code(Solution 2))

这数位(DP)和高维前缀和真是累死人不偿命。。。

#include <cstdio>
#include <cstring>
#define mo 998244353
#define db double
#define ll long long
#define mem(x, a) memset(x, a, sizeof x)
#define mpy(x, y) memcpy(x, y, sizeof y)
#define fo(x, a, b) for (int x = (a); x <= (b); x++)
#define fd(x, a, b) for (int x = (a); x >= (b); x--)
#define go(x) for (int p = tail[x], v; p; p = e[p].fr)
#define plus(x, y) x = x + y >= mo ? x + y - mo : x + y
#define nplus(x, y) x = x + mo - y >= mo ? x - y : x + mo - y
using namespace std;
const int fen[10][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}, 
						{1, 0, 0, 0}, {0, 1, 0, 0},
						{2, 0, 0, 0}, {0, 0, 1, 0},
						{1, 1, 0, 0}, {0, 0, 0, 1},
						{3, 0, 0, 0}, {0, 2, 0, 0}};
int f[61][39][27][23], g[61][39][27][23], len, ans = 0;
int las_[4];
ll n, K, cf[19], cf0[4][60];
bool nonono = 0;

int get_len(ll x) {
	int s = 0; while (x) s++, x /= 10;
	cf[0] = 1; fo(i, 1, s) cf[i] = cf[i - 1] * 10;
	return s;
}


int main()
{
	freopen("lover.in", "r", stdin);
	freopen("lover.out", "w", stdout);
	scanf("%lld%lld", &n, &K);
	len = get_len(n);
	
	int fir_ = n / cf[len - 1] % 10;
	fo(i, 1, fir_ - 1) f[fen[i][0]][fen[i][1]][fen[i][2]][fen[i][3]] = 1;
	fo(i, 0, 3) las_[i] = fen[fir_][i];
	
	cf0[0][0] = cf0[1][0] = cf0[2][0] = cf0[3][0] = 1;
	fo(i, 1, 59) cf0[0][i] = cf0[0][i - 1] << 1;
	fo(i, 1, 37) cf0[1][i] = cf0[1][i - 1] * 3;
	fo(i, 1, 25) cf0[2][i] = cf0[2][i - 1] * 5;
	fo(i, 1, 21) cf0[3][i] = cf0[3][i - 1] * 7;
	
	fo(i, 2, len) {
		int val = n / cf[len - i] % 10;
		if (val == 0) nonono = 1;
		mpy(g, f); mem(f, 0);
		fo(j, 0, 59) {
			if (cf0[0][j] > cf[i - 1]) break;
			fo(k, 0, 37) {
			if (cf0[0][j] * cf0[1][k] > cf[i - 1]) break;
			fo(l, 0, 25) {
			if (cf0[0][j] * cf0[1][k] * cf0[2][l] > cf[i - 1]) break;
			fo(p, 0, 21) {
			if (cf0[0][j] * cf0[1][k] * cf0[2][l] * cf0[3][p] > cf[i - 1]) break;
			if (! g[j][k][l][p]) continue;
			fo(q, 1, 9) {
				if (j + fen[q][0] > 59 || k + fen[q][1] > 37 || l + fen[q][2] > 25 || p + fen[q][3] > 21) continue;
				plus(f[j + fen[q][0]][k + fen[q][1]][l + fen[q][2]][p + fen[q][3]], g[j][k][l][p]);
			}
			}
			}
			}
		}
		
		fo(q, 1, 9) plus(f[fen[q][0]][fen[q][1]][fen[q][2]][fen[q][3]], 1);
		if (nonono == 0) {
			fo(q, 1, val - 1)
				plus(f[las_[0] + fen[q][0]][las_[1] + fen[q][1]][las_[2] + fen[q][2]][las_[3] + fen[q][3]], 1);
		}
		fo(j, 0, 3) las_[j] += fen[val][j];
	}
	if (nonono == 0) f[las_[0]][las_[1]][las_[2]][las_[3]]++;
	/*
	fo(j, 0, 59) fo(k, 0, 37) fo(l, 0, 25) fo(p, 0, 21) {
		if (! f[j][k][l][p]) continue;
		printf("%d %d %d %d, %lld
", j, k, l, p, cf0[0][j] * cf0[1][k] * cf0[2][l] * cf0[3][p]);
		printf("%d
", f[j][k][l][p]);
	}
	return 0;
	*/
	fd(j, 59, 0) fd(k, 37, 0) fd(l, 25, 0) fd(p, 21, 0)
		plus(f[j][k][l][p], f[j + 1][k][l][p]);
	fd(j, 59, 0) fd(k, 37, 0) fd(l, 25, 0) fd(p, 21, 0)
		plus(f[j][k][l][p], f[j][k + 1][l][p]);
	fd(j, 59, 0) fd(k, 37, 0) fd(l, 25, 0) fd(p, 21, 0)
		plus(f[j][k][l][p], f[j][k][l + 1][p]);
	fd(j, 59, 0) fd(k, 37, 0) fd(l, 25, 0) fd(p, 21, 0)
		plus(f[j][k][l][p], f[j][k][l][p + 1]);
	fo(j, 0, 59) fo(k, 0, 37) fo(l, 0, 25) fo(p, 0, 21)
		g[j][k][l][p] = (ll)f[j][k][l][p] * f[j][k][l][p] % mo;
	fo(j, 0, 59) fo(k, 0, 37) fo(l, 0, 25) fo(p, 0, 21)
		nplus(g[j][k][l][p], g[j + 1][k][l][p]);
	fo(j, 0, 59) fo(k, 0, 37) fo(l, 0, 25) fo(p, 0, 21)
		nplus(g[j][k][l][p], g[j][k + 1][l][p]);
	fo(j, 0, 59) fo(k, 0, 37) fo(l, 0, 25) fo(p, 0, 21)
		nplus(g[j][k][l][p], g[j][k][l + 1][p]);
	fo(j, 0, 59) fo(k, 0, 37) fo(l, 0, 25) fo(p, 0, 21)
		nplus(g[j][k][l][p], g[j][k][l][p + 1]);
		
	fo(j, 0, 59) {
		if (cf0[0][j] > K) break;
		fo(k, 0, 37) {
		if (cf0[0][j] * cf0[1][k] > K) break;
		fo(l, 0, 25) {
		if (cf0[0][j] * cf0[1][k] * cf0[2][l] > K) break;
		fo(p, 0, 21) {
			if (cf0[0][j] * cf0[1][k] * cf0[2][l] * cf0[3][p] > K) break;
			plus(ans, g[j][k][l][p]);
		}
	}
	}
	}
	printf("%d
", ans);
	return 0;
}
原文地址:https://www.cnblogs.com/jz929/p/13871004.html