LGP3303题解

不懂为什么是黑的,这不是傻ber题吗。

容易发现一件事,有值的位置上,横纵坐标一定只包含 \(2,3,5,7\) 这几个质因数。

写个搜索算一下,只有 \(14672\) 个位置啊。

并且容易发现一定有 \(f(i)<i\),所以可以随便写一个数位 DP 算每个位置上有多少个数。

然后用个堆维护维护就随随便便 \(K\log 14672\) 了。。。

所以重点就是考虑怎么做数位 DP。

\(a,b,c,d\) 分别是 \(2,3,5,7\) 的倍数,枚举和 \(n\) 相同的前缀然后枚举下一位不同。问题变为所有 \(i\) 位数中有多少个数满足 \(f(n)=2^a3^b5^c7^d\)

很显然 \(5\)\(7\) 都只能有一个,问题变为 \(i-c-d\) 位数中有多少个数满足 \(f(n)=2^a3^b\),最后乘上一个 \(\binom{i}{c,d,i-c-d}\) 就行了。

所有可能的数码是 \(1,2,3,4,6,8,9\)。只有 \(6\) 最特殊,设答案为 \(f[n][a][b]\),先枚举 \(6\) 的数量。

\(g1[n][m]\) 表示 \(n\) 位数中一共使用 \(m\)\(2\) 的方案数,\(g2[n][m]\) 表示使用 \(m\)\(3\) 的方案数。

那么 \(f[n][a][b]=\sum_{i=0}^{n}\binom{n}{i}\sum_{x+y=n-i}\binom{x+y}{x}g1[x][a-i]\times g2[y][b-i]\)

可以知道 \(g1[n][m]=[x^m](x+x^2+x^3)^n\)

\[g1[n][m]=[x^{m-n}](1+x+x^2)^n \]

\[g1[n][m]=[x^{m-n}](\frac{1}{1-x})^n(\sum_{i=0}^{n}(-1)^i\binom{n}{i}x^{3i}) \]

\[g1[n][m]=\sum_{i=0}^{\min(n,\lfloor\frac{m-n}{3}\rfloor)}(-1)^{i}\binom{n}{i}\binom{m-n-3i+n-1}{n-1} \]

\[g1[n][m]=\sum_{i=0}^{\min(n,\lfloor\frac{m-n}{3}\rfloor)}(-1)^{i}\binom{n}{i}\binom{m-3i-1}{n-1} \]

同理有:

\[g2[n][m]=[x^m](x+x^2)^n \]

\[g2[n][m]=[x^{m-n}](1+x)^n=\binom{n}{m-n} \]

\(a,b,c,d\) 的上界为 \(m\)\(n\) 的位数为 \(k\),那么预处理的复杂度是 \(O(n^3m^2)\),随便乱草。

对于 \(1\) 的处理在最外部再套一个组合数就好了。。。

#include<algorithm>
#include<cstdio>
#include<queue>
typedef long long ll;
const int N=15,M=55,mod=1e9+7,p[]={2,3,5,7};
int n,k,x[N],C[M][M],g1[N][M],g2[N][M],f[N][M][M];ll tn;int pri[4];int m,id[15000],cnt[15000];
struct nd{
	int id;ll V;
	inline bool operator<(const nd&it)const{
		return V<it.V;
	}
};std::priority_queue<nd>q;
inline int Add(const int&a,const int&b){
	return a+b>=mod?a+b-mod:a+b;
}
inline void init(){
	f[0][0][0]=g1[0][0]=g2[0][0]=C[0][0]=1;for(int i=1;i<=50;++i)C[i][0]=1;
	for(int i=1;i<=50;++i)for(int j=1;j<=i;++j)C[i][j]=Add(C[i-1][j],C[i-1][j-1]);
	for(int i=1;i<=12;++i){
		for(int j=i;j<=i*3;++j){
			for(int k=0;k<=i&&k*3<=j-i;++k)g1[i][j]+=(k&1?-1:1)*C[i][k]*C[j-3*k-1][i-1];
		}
		for(int j=i;j<=i*2;++j)g2[i][j]=C[i][j-i];
		for(int x=0;x<=i*3;++x)for(int y=0;y<=i*2;++y)for(int k=0;k<=i;++k){
			f[i][x][y]+=g1[k][x]*g2[i-k][y]*C[i][k];
		}
	}
	for(int i=12;i>=1;--i)for(int x=0;x<=i*3;++x)for(int y=0;y<=i*2;++y){
		for(int k=1;k<=i&&k<=x&&k<=y;++k)f[i][x][y]+=C[i][k]*f[i-k][x-k][y-k];
	}
	for(int i=12;i>=1;--i)for(int x=0;x<=i*3;++x)for(int y=0;y<=i*2;++y){
		for(int k=1;k<=i;++k)f[i][x][y]+=C[i][k]*f[i-k][x][y];
	}
}
inline int cal(const int&n,const int&a,const int&b,const int&c,const int&d){
	return c+d>n?0:1ll*C[n][c]*C[n-c][d]*f[n-c-d][a][b];
}
inline int calc(int a,int b,int c,int d){
	int sum(0);
	for(int i=2;i<=n;++i)sum+=cal(i-1,a,b,c,d);
	for(int i=n;i>=1;--i){
		if(a<0||b<0||c<0||d<0)break;
		for(int t=1;t<x[i]+(i==1);++t){
			if(t==1)sum+=cal(i-1,a,b,c,d);
			if(t==2)sum+=cal(i-1,a-1,b,c,d);
			if(t==3)sum+=cal(i-1,a,b-1,c,d);
			if(t==4)sum+=cal(i-1,a-2,b,c,d);
			if(t==5)sum+=cal(i-1,a,b,c-1,d);
			if(t==6)sum+=cal(i-1,a-1,b-1,c,d);
			if(t==7)sum+=cal(i-1,a,b,c,d-1);
			if(t==8)sum+=cal(i-1,a-3,b,c,d);
			if(t==9)sum+=cal(i-1,a,b-2,c,d);
		}
		if(x[i]==0)break;
		if(x[i]==2)a-=1;
		if(x[i]==3)b-=1;
		if(x[i]==4)a-=2;
		if(x[i]==5)c-=1;
		if(x[i]==6)a-=1,b-=1;
		if(x[i]==7)d-=1;
		if(x[i]==8)a-=3;
		if(x[i]==9)b-=2;
	}
	return sum;
}
inline void DFS(ll n,const int&id){
	if(id==4)return cnt[++m]=calc(pri[0],pri[1],pri[2],pri[3]),void();
	pri[id]=0;while(n<=tn)DFS(n,id+1),++pri[id],n*=p[id];
}
signed main(){
	int ans(0);init();scanf("%lld%d",&tn,&k);ll tmp=tn;for(n=1;tmp;++n)x[n]=tmp%10,tmp/=10;--n;DFS(1,0);
	std::sort(cnt+1,cnt+m+1,[&](const ll&a,const ll&b){return a>b;});while(!cnt[m])--m;
	for(int i=1;i<=m;++i)q.push((nd){i,1ll*cnt[i]*cnt[id[i]=1]});
	while(!q.empty()&&k--){
		const nd u=q.top();q.pop();ans=(ans+u.V)%mod;
		if(id[u.id]<m)q.push((nd){u.id,1ll*cnt[u.id]*cnt[++id[u.id]]});
	}
	printf("%d",ans);
}
posted @ 2022-07-13 11:17  Prean  阅读(15)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};