[ BZOJ 2757 ]Blinker的仰慕者
Blinker的仰慕者[L,R] 之间满足各位数字乘积为\(k\) 的数字有多少个.\((L,R \leq 10^{18})\)
-
\(f[i][j][k]:\) 前\(i\)位数,\(j\)代表与上限的大小关系,\(k\)是积
- \(k\) 太大:上限可达 \(9^{18}\)
-
优化:因为每次都是乘\([0,9]\)之间的整数,因此可以将\(k\)拆成四维,则状态为:
- \(f[i][j][a][b][c][d]\) 其中\(i,j\)的含义不变,\(a,b,c,d\)各代表\(2,3,5,7\)的指数.
但是还是太大!因为状态一共有 \(18\times 2\times log_210^{18}\times log_310^{18}\times log_510^{18}\times log_710^{18} = 44543912\)
此时将[\(1,10^{18}\)]范围内所有质因子只有\(2,3,5,7\)的数字统计一遍,发现只有 \(66061\) 个数
因此可以先打一个表,记录 \([1,10^{18}]\) 之间质因子只含有 \(2,3,5,7\) 的数字个数.
状态:\(f[i][j]\) 为前 \(i\) 个数,乘积为表中的第\(j\)项时的方案数.
数表生成器:
typedef long long ll;
priority_queue<ll,vector<ll>,greater<ll> >q;
vector<ll>ans;
map<ll,bool>vis;
void gen(vector<ll>& ans,const ll& maxn) {//生成 [1,maxn] 中质因子只包含 2,3,5,7 的数字,保存在 ans 中。
const ll b[4]= {2,3,5,7};
q.push(1);
vis[1]=1;
while(!q.empty()) {
ll u=q.top();
q.pop();
ans.push_back(u);
for(int i=0; i<4; i++) {
ll v=u*b[i];
if(!vis.count(v) && v<=maxn) {
q.push(v);
vis[v]=1;
}
}
}
sort(ans.begin(),ans.end());
}