P3303 [SDOI2013] 淘金


是个简单题,可惜我代码暂时写挂了,起床再来改()

显然先要求出 \(cnt(f(i)),(i \in [1,N]),cnt(x)\) 表示 \(x\) 的出现次数。求出来之后两两相乘贪心即可。

\(f(i)\) 最大可能是 \(10^{12}\) ,省略掉了大于 \(N\) 的情况。所以要探讨下 \(f(i)\) 的不同取值数量。

mapmp;
map,bool>vis;
int tot=0;
void dfs(int x,ll num) {
	if(vis[make_pair(x,num)]) return ;
	if(x==13) {
		if(!mp[num]) mp[num]=1,++tot;
		return ;
	} 
	for(int i=1;i<=9;i++) dfs(x+1,num*i);
	vis[make_pair(x,num)]=1;
} 

int main() {
	dfs(1,1); cout<

打表发现有 8282 种可能。

考虑求出 \(cnt(f(i))\) ,这个枚举下之后数位 dp 即可,即枚举 \(f(i)\),然后考虑找一堆一些数使得乘积为 \(f(i)\),这里直接转化为找到一些数,使得这些数各位都是 \(f(i)\) 的因数。用 \(f[x][id]\) 表示当前第 \(x\) 位,目前剩余的数是 \(map[id]\) 的答案,对于边界,当且仅当 \(map[id]=1\) 时能有贡献。

\(\text{Code}\)

#include 

#define ll long long

using namespace std;
int rd() {
	int f=1,sum=0; char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return sum*f;
}
ll lrd() {
	ll f=1,sum=0; char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
	return sum*f;
}

const int mod=(int)(1e9+7);
unordered_mapmp;
ll f[15][8300];
ll a[8300],acnt[8300];
int num[15],tot,cnt;
ll n,m;

ll dfs(int lim,int x,int id) {
	if(!x) return a[id]==1;
	if(!lim&&~f[x][id]) return f[x][id];
//	cout<vis[14];
	void dfs(int x,ll number) {
		if(vis[x].count(number)) return ;
		if(x==13) {
			if(!mp[number]) a[++cnt]=number,mp[number]=1;
			return ;
		} 
		for(int i=1;i<=9;i++) dfs(x+1,number*i);
		vis[x][number]=1;
	}
}

bool cmp(ll x,ll y) {
	return x>y;
}
priority_queueq;
int main() {
	n=lrd(); m=lrd(); ll x=n;
	while(x) num[++tot]=x%10,x/=10;
	xgf::dfs(1,1); a[++cnt]=(ll)(1e12),mp[a[cnt]]=cnt; sort(a+1,a+1+cnt);
	for(int i=1;i<=cnt;i++) mp[a[i]]=i;
	memset(f,-1,sizeof(f));
	for(int i=1;i<=cnt;i++) {
		if(a[i]>n) {
			cnt=i-1; break;
		}
		for(int j=1;j<=tot;j++) acnt[i]+=dfs(j==tot,j,i);
	//	cout<