gmoj 6831. 2020.10.24【NOIP提高A组】lover 题解

题目

https://gmoj.net/senior/#main/show/6831

题解

这道题的 d i g dig dig函数定义貌似不太清楚,令 l e n ( 1 ≤ l e n ≤ n ) len\quad( 1\le len\leq n) len(1lenn)表示正整数x在十进制下的数位,若 x = ( x 1 x 2 x 3 . . . x l e n − 1 x l e n ) 10 x=(x_1x_2x_3...x_{len-1}x_{len})_{10} x=(x1x2x3...xlen1xlen)10,那么 d i g ( x ) = ∏ i = 1 l e n x i dig(x)=\prod_{i=1}^{len}x_i dig(x)=i=1lenxi

考场上没有由gcd想到找质数。其实这个想法是很关键的(据说也很显然),发现10以内的质数只有2、3、5、7,可以很暴力地统计。

f x , 0 / 1 , i , j , k , l f_{x,0/1,i,j,k,l} fx,0/1,i,j,k,l表示当前考虑到数的从高到低数的第x位(不足x位的补前缀0,注意前缀0不能乘到dig中),当前数字的前x位是否等于n的前x位, d i g = 2 i × 3 j × 5 k × 7 l dig=2^i\times 3^j\times 5^k\times 7^l dig=2i×3j×5k×7l,满足这些条件的数的个数。

f 直接枚举当前位置上的数转移即可,注意处理有前缀0的情况。

接着考虑统计答案。显然答案等于 ∑ 2 a × 3 b × 5 c × 7 d ≥ k ∑ i ≥ a , j ≥ b , k ≥ c , l ≥ d ∑ i ′ ≥ a , j ′ ≥ b , k ′ ≥ c , l ′ ≥ d f n , 0 / 1 , i , j , k , l × f n , 0 / 1 , i ′ , j ′ , k ′ , l ′ \sum_{2^a\times 3^b\times 5^c\times 7^d\geq k}\sum_{i\ge a,j\ge b,k\ge c,l\ge d}\sum_{i'\ge a,j'\ge b,k'\ge c,l'\ge d}f_{n,0/1,i,j,k,l}\times f_{n,0/1,i',j',k',l'} 2a×3b×5c×7dkia,jb,kc,ldia,jb,kc,ldfn,0/1,i,j,k,l×fn,0/1,i,j,k,l

但是直接枚举显然不行,因此考虑后缀和优化。

设后缀和数组 g s , i , j , k , l g_{s,i,j,k,l} gs,i,j,k,l,s表示一个 [ 0 , 15 ] [0,15] [0,15]的二进制状态。若记录的数为 2 a × 3 b × 5 c × 7 d 2^a\times 3^b\times 5^c\times 7^d 2a×3b×5c×7d,第一位为1表示记录的数a=i;否则a>i。第二三四位同理。这里为什么不用大于等于呢?因为这样虽然统计答案略显方便,但是难以转移。

g的转移比较特殊,要先将 g 15 g_{15} g15求出,再用它转移出其它状态,“大于”由+1的“大于”或“等于”转移过来,等于则由数字相同的“等于”转移过来。

最后统计答案的时候,为了避免算重,要保证 gcd ⁡ ( 2 i × 3 j × 5 k × 7 l , 2 i ′ × 3 j ′ × 5 k ′ × 7 l ′ ) = 2 a × 3 b × 5 c × 7 d \gcd(2^i\times 3^j\times 5^k\times 7^l,2^{i'}\times 3^{j'}\times 5^{k'}\times 7^{l'})=2^a\times 3^b\times 5^c\times 7^d gcd(2i×3j×5k×7l,2i×3j×5k×7l)=2a×3b×5c×7d,即前一个数对应的状态 s 和后一个数对应的状态 t 满足 s ∣ t = 15 s|t=15 st=15

注意常数优化(我是打了一个晚上,又调了好久,迫不得已才加上Ofast的,其实缩小循环范围也能过)。

CODE

#pragma GCC optimize("fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-std=c++14"
#pragma GCC target("sse3","sse2","sse")
#pragma GCC optimize("Ofast")
#include<cstring>
#include<cstdio>
using namespace std;
typedef long long ll;
#define P 998244353
#define loop for(int a=0;a<=n1;++a) for(int b=0;b<=n2;++b) for(int c=0;c<=n3;++c) for(int d=0;d<=n4;++d)
const int num[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[2][2][65][45][35][25],g[16][65][45][35][25],h[65][45][35][25],lim[25];
ll pow[4][65];
inline void add1(int &x,int y){
    
    x+=y;if(x>=P) x-=P;}
inline int add2(int x,int y){
    
    x+=y;if(x>=P) x-=P;return x;}
inline void minus(int &x,int y){
    
    x-=y;if(x<0) x+=P;}
int main()
{
    
    
	freopen("lover.in","r",stdin);
	freopen("lover.out","w",stdout);
	ll n,k,x,tmp;int ans=0,n1,n2,n3,n4,m,t;
	scanf("%lld%lld",&n,&k);
	for(n1=0,pow[0][0]=1;pow[0][n1]<=n;pow[0][n1+1]=pow[0][n1]*2,++n1);--n1;
	for(n2=0,pow[1][0]=1;pow[1][n2]<=n;pow[1][n2+1]=pow[1][n2]*3,++n2);--n2;
	for(n3=0,pow[2][0]=1;pow[2][n3]<=n;pow[2][n3+1]=pow[2][n3]*5,++n3);--n3;
	for(n4=0,pow[3][0]=1;pow[3][n4]<=n;pow[3][n4+1]=pow[3][n4]*7,++n4);--n4;
	for(m=0,x=1;x<=n;x*=10,++m);
	x/=10;for(int i=1;i<=m;++i,x/=10) lim[i]=n/x%10;
	f[0][1][0][0][0][0]=1;
	for(int i=1;i<=m;++i)
	{
    
    
		t=i&1,memset(f[t],0,sizeof f[t]);
		for(int a=0;a<=n1&&a<=3*i;++a)
			for(int b=0;b<=n2&&a+b<=3*i;++b)
				for(int c=0;c<=n3&&a+b+c<=3*i;++c)
					for(int d=0;d<=n4&&a+b+c+d<=3*i;++d)
					{
    
    
						if(lim[i])
						{
    
    
							for(int j=1;j<lim[i];++j) add1(f[t][0][a+num[j][0]][b+num[j][1]][c+num[j][2]][d+num[j][3]],f[t^1][1][a][b][c][d]);
							add1(f[t][1][a+num[lim[i]][0]][b+num[lim[i]][1]][c+num[lim[i]][2]][d+num[lim[i]][3]],f[t^1][1][a][b][c][d]);
						}
						for(int j=1;j<10;++j) add1(f[t][0][a+num[j][0]][b+num[j][1]][c+num[j][2]][d+num[j][3]],f[t^1][0][a][b][c][d]);
					}
		++f[t][0][0][0][0][0];
	}
	loop h[a][b][c][d]=add2(f[t][0][a][b][c][d],f[t][1][a][b][c][d]);
	minus(h[0][0][0][0],1);
	loop g[15][a][b][c][d]=h[a][b][c][d];
	for(int a=n1;a>=0;--a) for(int b=n2;b>=0;--b) for(int c=n3;c>=0;--c) for(int d=n4;d>=0;--d)
		for(int s=14,aa,bb,cc,dd;s>=0;--s)
		{
    
    
			aa=a,bb=b,cc=c,dd=d;
			if(!(s&1)) ++aa;if(!(s&2)) ++bb;
			if(!(s&4)) ++cc;if(!(s&8)) ++dd;
			for(tmp=0,t=s;t<16;++t) if((s&t)==s)
				add1(g[s][a][b][c][d],g[t][aa][bb][cc][dd]);
		}
	loop if(pow[0][a]*pow[1][b]*pow[2][c]*pow[3][d]<=k)
		for(int i=0;i<16;++i) for(int j=i^15;j<16;++j) if((i|j)==15)
			add1(ans,1LL*g[i][a][b][c][d]*g[j][a][b][c][d]%P);
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huangzihaoal/article/details/109319381
今日推荐