BZOJ 3679 数位DP,离散化
2017-05-10 20:20
246 查看
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3679
解法: 比较裸的数位DP,dp[i][j][k]表示前i位,当前位数字为j,乘积为k(k保存的是离散化之后的值),然后按照数位DP的做法去写就可以了。
DFS版本:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL dp[20][6000];
LL n;
int cnt,a[20];
map<LL,int> use;
LL dfs(int pos,LL chengji,bool lead,bool limit)
{
if(chengji>n)
return 0;
if(use[chengji]==0)
{
use[chengji]=cnt++;
}
if(pos==-1)
{
if(chengji>0&&chengji<=n)
return 1;
return 0;
}
if(lead==1&&!limit&&dp[pos][use[chengji]]!=-1)
return dp[pos][use[chengji]];
int up=limit ? a[pos]:9;
LL ret=0;
for(int i=0;i<=up;i++)
{
if(i==0)
{
if(lead==true)
ret+=dfs(pos-1,chengji*i,true,limit&&i==a[pos]);
else
ret+=dfs(pos-1,0,false,limit&&i==a[pos]);
}
else
{
if(lead==true)
ret+=dfs(pos-1,chengji*i,true,limit&&i==a[pos]);
else
ret+=dfs(pos-1,i,true,limit&&i==a[pos]);
}
}
if(!limit&&lead)
dp[pos][use[chengji]]=ret;
return ret;
}
LL solve(LL x)
{
int pos=0;
while(x)
{
a[pos++]=x%10;
x/=10;
}
return dfs(pos-1,0,false,true);
}
int main()
{
memset(dp,-1,sizeof(dp));
LL l,r;
use.clear();
cnt=1;
scanf("%lld",&n);
scanf("%lld%lld",&l,&r);
LL ans=solve(r-1)-solve(l-1);
printf("%lld\n",ans);
return 0;
}
解法: 比较裸的数位DP,dp[i][j][k]表示前i位,当前位数字为j,乘积为k(k保存的是离散化之后的值),然后按照数位DP的做法去写就可以了。
///BZOJ 3679 ///数位DP,离散化 #include <bits/stdc++.h> using namespace std; typedef long long LL; LL dp[20][10][6000]; ///dp[i][j][k]前i位,当前位数字为j,乘积为k(k保存的是离散化之后的值) LL l, r; int digit[20]; int a[6000]; int n, tot, num; map<LL,int>p; ///2,3,5,7 bool check(int a, int b, int c, int d){ long long ans=1; for(int i=1; i<=a; i++) ans*=2; if(ans>n) return 0; for(int i=1; i<=b; i++) ans*=3; if(ans>n) return 0; for(int i=1; i<=c; i++) ans*=5; if(ans>n) return 0; for(int i=1; i<=d; i++) ans*=7; if(ans>n) return 0; return 1; } int cal(int a, int b, int c, int d){ int ans=1; for(int i=1; i<=a; i++) ans*=2; for(int i=1; i<=b; i++) ans*=3; for(int i=1; i<=c; i++) ans*=5; for(int i=1; i<=d; i++) ans*=7; return ans; } long long f(LL x){ LL ans=0; num=0; while(x){ digit[++num]=x%10; x/=10; } for(int i=1; i<=num/2; i++) swap(digit[i],digit[num-i+1]); for(int i=1; i<num; i++) for(int j=1; j<=9; j++) for(int k=1; k<=tot; k++) ans += dp[num-i][j][k]; LL sum=1; for(int i=1; i<=num; i++){ for(int j=1; j<digit[i]; j++){ for(int k=1; k<=tot; k++){ if(a[k]*sum>n) break; ans+=dp[num-i+1][j][k]; } } sum*=digit[i]; if(sum>n||sum==0) break; } return ans; } int main(){ scanf("%d", &n); for(int i=0; i<=31; i++){ for(int j=0; j<=18; j++){ for(int k=0; k<=13; k++){ for(int l=0; l<=10; l++){ if(check(i,j,k,l)){ a[++tot]=cal(i,j,k,l); } } } } } sort(a+1,a+tot+1); for(int i=1; i<=tot; i++) p[a[i]]=i; scanf("%lld%lld",&l,&r); for(int i=1; i<=9; i++) if(p[i]) dp[1][i][p[i]]=1; for(int i=1; i<=18; i++){ for(int j=1; j<=9; j++){ for(int q=1; q<=tot; q++){ if(dp[i][j][q]){ for(int k=1; k<=9; k++){ if((long long)a[q]*k<=n && p[a[q]*k]) dp[i+1][k][p[a[q]*k]]+=dp[i][j][q]; } } } } } long long ans = f(r)-f(l); printf("%lld\n", ans); return 0; }
DFS版本:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL dp[20][6000];
LL n;
int cnt,a[20];
map<LL,int> use;
LL dfs(int pos,LL chengji,bool lead,bool limit)
{
if(chengji>n)
return 0;
if(use[chengji]==0)
{
use[chengji]=cnt++;
}
if(pos==-1)
{
if(chengji>0&&chengji<=n)
return 1;
return 0;
}
if(lead==1&&!limit&&dp[pos][use[chengji]]!=-1)
return dp[pos][use[chengji]];
int up=limit ? a[pos]:9;
LL ret=0;
for(int i=0;i<=up;i++)
{
if(i==0)
{
if(lead==true)
ret+=dfs(pos-1,chengji*i,true,limit&&i==a[pos]);
else
ret+=dfs(pos-1,0,false,limit&&i==a[pos]);
}
else
{
if(lead==true)
ret+=dfs(pos-1,chengji*i,true,limit&&i==a[pos]);
else
ret+=dfs(pos-1,i,true,limit&&i==a[pos]);
}
}
if(!limit&&lead)
dp[pos][use[chengji]]=ret;
return ret;
}
LL solve(LL x)
{
int pos=0;
while(x)
{
a[pos++]=x%10;
x/=10;
}
return dfs(pos-1,0,false,true);
}
int main()
{
memset(dp,-1,sizeof(dp));
LL l,r;
use.clear();
cnt=1;
scanf("%lld",&n);
scanf("%lld%lld",&l,&r);
LL ans=solve(r-1)-solve(l-1);
printf("%lld\n",ans);
return 0;
}
相关文章推荐
- BZOJ 3679 数位DP
- [BZOJ3679][数位DP]数字之积
- 【bzoj3679】 数字之积 数位dp
- [BZOJ3679]数字之积 数位DP
- BZOJ 3679 数字之积 - 数位dp
- BZOJ 3679 数字之积 (数位DP)
- [BZOJ]3679: 数字之积 数位DP
- 【bzoj1799】 AHOI2009 同类分布 数位dp
- [BZOJ1026]SCOI2009 windy数|数位DP
- 【bzoj 4521】 [Cqoi2016]手机号码(数位dp)
- [数位dp] bzoj 3209 花神的数论题
- BZOJ 4521: [Cqoi2016]手机号码 数位dp
- [数位DP 高精度 拓扑排序 bitset] BZOJ 2913 [Poi1997]XOR Gates
- 【数位DP】[BZOJ 3876]支线剧情
- bzoj:1026: [SCOI2009]windy数(数位dp)
- bzoj3652 大新闻(数位DP)
- 【BZOJ 3652】大新闻 数位dp+期望概率dp
- 【BZOJ1833】【ZJOI2010】数字计数 数位DP
- 【数位DP】【bzoj 1799】: [Ahoi2009]self 同类分布
- [BZOJ1799][Ahoi2009]self 同类分布(数位dp)