数位DP
数位DP
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=20;
int a,b,s[N],ten[N],dp[N][N][2][2];
/*
记录状态为
走到第p位,目前答案是多少
还有多少约束条件就再开多少维
是否达到上界(limit),是否有前导0(lead)
的情况下往后走可以得到多少这个数
*/
int dfs(int p,其他约束条件,int sum,int limit,int lead)
{
if(!p) return sum;也有可能不是返回sum,在下面的例题里有这种情况
if(dp[p][sum][limit][lead]!=-1) return dp[p][sum][limit][lead];
int up=limit?上限:s[p],ans=0;
for(int i=0;i<=up;++i)
ans+=dfs(p-1,其他约束条件,sum+(i==d&&(d||lead)),limit||i<up,i||lead,d);
return dp[p][sum][limit][lead]=ans;
}
inline int work(int x,int d)
{
memset(dp,-1,sizeof(dp));
s[0]=0;
while(x) s[++s[0]]=x%10,x/=10;
return dfs(s[0],0,0,0,d);
}
signed main()
{
输入和求值
}
P2657[SCOI2009] windy数


#include<bits/stdc++.h>
using namespace std;
const int N=15;
int n,a[N],dp[N][N];
void init()
{
for(int i=0;i<=9;++i) dp[1][i]=1;
for(int i=2;i<=10;++i)
for(int j=0;j<=9;++j)
for(int k=0;k<=9;++k)
if(abs(j-k)>=2) dp[i][j]+=dp[i-1][k];
}
int query(int x)
{
a[0]=0;
while(x) a[++a[0]]=x%10,x/=10;
int res=0;
for(int i=1;i<a[0];++i)
for(int j=1;j<=9;++j)
res+=dp[i][j];
// cout<<res<<" ";
for(int i=1;i<a[a[0]];++i)
res+=dp[a[0]][i];
// cout<<res<<" ";
for(int i=a[0]-1;i;--i)
{
for(int j=0;j<a[i];++j)
if(abs(j-a[i+1])>=2) res+=dp[i][j];
if(abs(a[i+1]-a[i])<2) break;
}
// cout<<res<<"\n";
return res;
}
int main()
{
init();
int x,y;
cin>>x>>y;
cout<<query(y+1)-query(x);
}
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=20;
int a,b,s[N],ten[N],dp[N][N][2][2];
/*
记录状态为
走到第p位,当前所求数字有sum个,
是否达到上界(limit),是否有前导0(lead)
的情况下往后走可以得到多少这个数
*/
int dfs(int p,int sum,int limit,int lead,int d)
{
if(!p) return sum;
if(dp[p][sum][limit][lead]!=-1) return dp[p][sum][limit][lead];
int up=limit?9:s[p],ans=0;
for(int i=0;i<=up;++i)
ans+=dfs(p-1,sum+(i==d&&(d||lead)),limit||i<up,i||lead,d);
return dp[p][sum][limit][lead]=ans;
}
inline int work(int x,int d)
{
memset(dp,-1,sizeof(dp));
s[0]=0;
while(x) s[++s[0]]=x%10,x/=10;
return dfs(s[0],0,0,0,d);
}
signed main()
{
cin>>a>>b;
for(int i=0;i<=9;++i)
cout<<work(b,i)-work(a-1,i)<<" ";
}
P4999 烦人的数学作业
双 倍 经 验
本题相当于求\([L,R]\)之间每个数字出现的次数\(cnt\),然后\(ans+=i*cnt[i]\)就可以得到最终答案。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=20;
int a,b,ans,mod=1e9+7,s[N],ten[N],dp[N][N][2][2];
int dfs(int p,int sum,int limit,int lead,int d)
{
if(!p) return sum;
if(dp[p][sum][limit][lead]!=-1) return dp[p][sum][limit][lead];
int up=limit?9:s[p],ans=0;
for(int i=0;i<=up;++i)
ans=(ans+dfs(p-1,sum+(i==d&&(d||lead)),limit||i<up,i||lead,d))%mod;
return dp[p][sum][limit][lead]=ans;
}
inline int work(int x,int d)
{
memset(dp,-1,sizeof(dp));
s[0]=0;
while(x) s[++s[0]]=x%10,x/=10;
return dfs(s[0],0,0,0,d);
}
signed main()
{
int T;scanf("%lld",&T);
while(T--)
{
int ans=0;
scanf("%lld %lld",&a,&b);
for(int i=0;i<=9;++i) ans=(ans+i*(work(b,i)-work(a-1,i)+mod)%mod)%mod;
printf("%lld\n",ans);
}
}
P1836 数页码
三 倍 经 验
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=20;
int a,b,ans,s[N],ten[N],dp[N][N][2][2];
/*
记录状态为
走到第p位,当前所求数字有sum个,
是否达到上界(limit),是否有前导0(lead)
的情况下往后走可以得到多少这个数
*/
int dfs(int p,int sum,int limit,int lead,int d)
{
if(!p) return sum;
if(dp[p][sum][limit][lead]!=-1) return dp[p][sum][limit][lead];
int up=limit?9:s[p],ans=0;
for(int i=0;i<=up;++i)
ans=ans+dfs(p-1,sum+(i==d&&(d||lead)),limit||i<up,i||lead,d);
return dp[p][sum][limit][lead]=ans;
}
inline int work(int x,int d)
{
memset(dp,-1,sizeof(dp));
s[0]=0;
while(x) s[++s[0]]=x%10,x/=10;
return dfs(s[0],0,0,0,d);
}
signed main()
{
int ans=0;
scanf("%lld",&a);
for(int i=0;i<=9;++i) ans=ans+i*work(a,i);
printf("%lld\n",ans);
}
P6218 [USACO06NOV] Round Numbers S
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=40;
int a,b,ans,s[N],ten[N],dp[N][N][N][2][2];
int tt;
/*
记录状态为
走到第p位,0有x0个,1有x1个
(只有不存在前导0的情况下才会对0计数)
是否达到上界(limit),是否有前导0(lead)
的情况下往后走可以得到多少这个数
*/
int dfs(int p,int x0,int x1,int limit,int lead)
{
if(!p) return x0>=x1;
if(dp[p][x0][x1][limit][lead]!=-1) return dp[p][x0][x1][limit][lead];
int up=limit?1:s[p],res=0;
for(int i=0;i<=up;++i)
if(i==0) res+=dfs(p-1,x0+lead,x1,limit||i<up,lead||i);
else res+=dfs(p-1,x0,x1+1,limit||i<up,lead||i);
return dp[p][x0][x1][limit][lead]=res;
}
inline int work(int x)
{
memset(dp,-1,sizeof(dp));
s[0]=0;
while(x) s[++s[0]]=x&1,x>>=1;
tt=(s[0]+1)/2;
return dfs(s[0],0,0,0,0);
}
signed main()
{
scanf("%lld %lld",&a,&b);
printf("%lld\n",work(b)-work(a-1));
}

浙公网安备 33010602011771号