1. 程式人生 > >【題解】[牛客網NOIP賽前集訓營-提高組(第一場)]B.數數字 線性DP

【題解】[牛客網NOIP賽前集訓營-提高組(第一場)]B.數數字 線性DP

題目連結
在這裡插入圖片描述


在這裡插入圖片描述
在這裡插入圖片描述

#include<cstdio>
#include<cstring>
typedef long long ll;
#define _rep(i,a,b) for(int i=(a);i<=(b);i++)
#define _for(i,a,b) for(int i=(a);i<(b);i++)
int co[10][10];
ll pw[10][100],l,r,l1,r1,ans,g[2][3][2][2],f[2][3][60][38][27][22];
ll nozero(ll x)
{
	if(x<=0)return 0;
	memset(f,0,sizeof(f));
	int cr=0;f[0][1][0][0][0][0]=1;
	ll ret=0,val;
	for(;x;x/=10,cr^=1)
	{
		int bit=x%10;
		memset(f[cr^1],0,sizeof(f[cr]));
		_for(i,0,3)_for(n2,0,60)_for(n3,0,38)_for(n5,0,27)_for(n7,0,22)if(val=f[cr][i][n2][n3][n5][n7])
		{
			ll q1=r1/pw[2][n2]/pw[3][n3]/pw[5][n5]/pw[7][n7];
			ll p1=(l1-1)/pw[2][n2]/pw[3][n3]/pw[5][n5]/pw[7][n7];
			if(q1>=1&&p1<=0)ret+=val;
			if(q1<=0)continue;
			_for(p,1,10)
			{
				int ni=(p>bit?2:(p==bit?i:0));
				int c2=n2+co[p][2];
				int c3=n3+co[p][3];
				int c5=n5+co[p][5];
				int c7=n7+co[p][7];
				if(c2>=60||c3>=38||c5>=27||c7>=22)continue;
				f[cr^1][ni][c2][c3][c5][c7]+=val;
			}
		}
	}
	_for(i,0,2)_for(n2,0,60)_for(n3,0,38)_for(n5,0,27)_for(n7,0,22)if(val=f[cr][i][n2][n3][n5][n7])
	{
		ll q1=r1/pw[2][n2]/pw[3][n3]/pw[5][n5]/pw[7][n7];
		ll p1=(l1-1)/pw[2][n2]/pw[3][n3]/pw[5][n5]/pw[7][n7];
		if(q1>=1&&p1<=0)ret+=val;
	}
	return ret;
}
ll zero(ll x)
{
	if(l1)return 0;//如果含0乘積為0
	memset(g,0,sizeof(g));
	int cr=0;ll ret=0;
	g[0][1][0][0]=1;
	for(;x;x/=10,cr^=1)
	{
		int bit=x%10;//取出該位
		memset(g[cr^1],0,sizeof(g[cr]));
		_for(i,0,3)_for(j,0,2)_for(hd,0,2)if(g[cr][i][j][hd])
		{
			if(hd&&j)ret+=g[cr][i][j][hd];
			_for(p,0,10)
			{
				int ni=(p>bit?2:(p==bit?i:0));
				int nj=(j|(p==0));
				int hdt=(p>0);
				g[cr^1][ni][nj][hdt]+=g[cr][i][j][hd];
			}
		}
	}
	return ret+g[cr][0][1][1]+g[cr][1][1][1];
}
ll calc(ll x)
{
	return zero(x)+nozero(x);
}
int main()
{
	//freopen("in.txt","r",stdin);
	_for(i,1,10)
	{
		_for(j,2,10)
		    for(int k=i;k%j==0;k/=j)
		        co[i][j]++;//預處理出i有多少個j因子 
		pw[i][0]=1;
		for(int j=1;j<=60;j++)
		    pw[i][j]=pw[i][j-1]*i;//預處理出i的次冪 
	}
	scanf("%lld%lld%lld%lld",&l,&r,&l1,&r1);
    if(!l)ans+=(l1==0),l++;
    if(l<=r)ans+=calc(r)-calc(l-1);
    printf("%lld\n",ans);
    return 0;
}

總結

線性DP好題,狀態定義是關鍵