P3303 [SDOI2013] 淘金

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

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

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

map<ll,bool>mp;
map<pair<int,ll>,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<<tot+1; //+1是因为还有1e12
}

打表发现有 8282 种可能。

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

\(\text{Code}\)

#include <bits/stdc++.h>

#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_map<ll,int>mp;
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<<x<<" "<<id<<endl;
	int nex=lim?num[x]:9; ll res=0;
	for(int i=1;i<=nex;i++) if(a[id]%i==0) res+=dfs(lim&(i==nex),x-1,mp[a[id]/i]);
	if(!lim) f[x][id]=res;
	return res;
}

namespace xgf {
	unordered_map<ll,bool>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_queue<ll>q;
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<<a[i]<<" "<<acnt[i]<<endl;
	}
	ll ans=0,qwq=sqrt(m);
	sort(acnt+1,acnt+1+cnt,cmp);
	for(int i=1;i<=min(1ll*cnt,qwq*4);i++) {
		for(int j=1;j<=min(1ll*cnt,qwq*4);j++) {
			if(q.size()<m) q.push(-1ll*acnt[i]*acnt[j]);
			else if(-q.top()<acnt[i]*acnt[j]) q.pop(),q.push(-1ll*acnt[i]*acnt[j]);
		}
	}
//	cout<<q.size()<<endl;
	while(!q.empty()) (ans+=-1ll*q.top())%=mod,q.pop();
	printf("%lld",ans);
	return 0;
}
posted @ 2022-02-08 18:10  FxorG  阅读(73)  评论(0)    收藏  举报