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;
}