数位dp:bzoj1799
一开始没有想到枚举所有模数求解,卡了很久。
写法见代码注释。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<stack> #include<map> #include<vector> #include<queue> #include<set> #include<iomanip> #include<cctype> #include<ctime> using namespace std; #define ll long long #define edl putchar('\n') #define sscc ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); #define FOR(i,a,b) for(int i=a;i<=b;i++) #define ROF(i,a,b) for(int i=a;i>=b;i--) #define FORLL(i,a,b) for(ll i=a;i<=b;i++) #define ROFLL(i,a,b) for(ll i=a;i>=b;i--) #define mst(a) memset(a,0,sizeof(a)) #define mstn(a,n) memset(a,n,sizeof(a)) #define zero(x)(((x)>0?(x):-(x))<eps) inline ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} inline ll lcm(ll a,ll b){return a/gcd(a,b)*b;} int month[15]={0,31,28,31,30,31,30,31,31,30,31,30,31}; const int MAXN=1e5+5; const int INF=1<<30; const long long mod=1e9+7; const double eps=1e-8; ll dp[25][170][170]; /*dp数组记录答案,第一维为第几位,第二维为当前数字模p的结果,第三维为数位和*/ int a[25],p,vis[25][170][170]; /*a数组记录每一位的值,p为模数,vis数组对应dp,代表在模p时是否访问过*/ ll dfs(int pos,int m,int sta,int limit)/*第几位 模后的数 数位和 上限*/ { if(pos==0) return sta==0&&m%p==0; if(!limit&&vis[pos][m][sta]==p) { return dp[pos][m][sta]; } vis[pos][m][sta]=p;/*更新vis访问标记*/ int up=limit?a[pos]:9; ll ans=0; FOR(i,0,up) { if(sta>=i) ans+=dfs(pos-1,(m*10+i)%p,sta-i,limit&&i==up); /*由于枚举p时数位和是固定的,所以直接用p减去数位和*/ } if(!limit) dp[pos][m][sta]=ans; return ans; } ll solve(ll x) { int pos=0,t; while(x) { a[++pos]=x%10; x/=10; } a[pos+1]=0; t=pos*9; ll ans=0; FOR(i,1,t) p=i,ans+=dfs(pos,0,i,1); return ans; } int main() { ll n,m; { scanf("%lld%lld",&n,&m); mst(vis); n=solve(n-1); mst(vis);/*每次处理都要对vis初始化*/ m=solve(m); printf("%lld\n",m-n); } return 0; }