数位dp 专题
先来模板:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
int dfs(int i,int s,bool e) ///枚举第i位,第i位前一位的数字为s,e表示前缀是否已达到上界。(如果未达到,则枚举0000...~9999..,反之枚举0000...~abcd...) { if(i==-1) return 1; if(!e&&~f[i][s]) return f[i][s];/// f记录的是位数为i,前一数字为s的0000..~9999...的符合条件的个数 int res=0; int u=e?num[i]:9; REP(d,0,u){ res+=dfs(i-1,d,e&&d==u)); } return d==u?res:f[i][s]=res; }
C题:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70324#problem/C
求[L,R]中不含62和4的数的个数。
f[i][s]为符合条件的数的个数,第一维i表示当前位数,第二维s表示前一位(第i+1位)的数字。
总算是过了第一道数位dp的题。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); int L,R; int num[110]; int f[110][11]; int dfs(int i,int s,bool e) { if(i==-1) return 1; if(!e&&~f[i][s]) return f[i][s]; int res=0; int u=e?num[i]:9; REP(d,0,u){ if(d==4||(s==6&&d==2)) continue; res+=dfs(i-1,d,e&&d==u); } return e?res:f[i][s]=res; } int F(int n) { MS0(num); int len=0; while(n){ num[len++]=n%10; n/=10; } MS1(f); return dfs(len-1,0,1); } int main() { //freopen("in.txt","r",stdin); while(cin>>L>>R,(L||R)){ cout<<F(R)-F(L-1)<<endl; } return 0; }
D题:
求[0,N]中含有49的数的个数。
先求不含49的个数k,注意总个数是N+1,(区间为[0,N],0也算一个)。
注意用unsigned long long。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll unsigned long long //#define ull unsigned long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); ll N; int num[120]; ll f[120][120]; ll dfs(int i,int s,bool e) { if(i==-1) return 1; if(!e&&~f[i][s]) return f[i][s]; ll res=0; int u=e?num[i]:9; REP(d,0,u){ if(s==4&&d==9) continue; res+=dfs(i-1,d,e&&d==u); } return e?res:f[i][s]=res; } ll F(ll N) { MS0(num); int len=0; ll t=N; while(t){ num[len++]=t%10; t/=10; } MS1(f); return N+1-dfs(len-1,0,1); } int main() { //freopen("in.txt","r",stdin); DRI(T); while(T--){ cin>>N; cout<<F(N)<<endl; } return 0; }
E题:
求[L,R]中二进制表示中0的个数比1的个数多或等的数的个数。
f[i][s][one][zero]:i表示当前位数,s,one,zero分别表示之前的数字,之前的1的个数,之前的0的个数(不含前导0)。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); ll L,R; int num[70]; ll f[70][2][70][70]; ll dfs(int i,int s,int one,int zero,bool e) { if(i==-1) return one<=zero; if(!e&&~f[i][s][one][zero]) return f[i][s][one][zero]; ll res=0; int u=e?num[i]:1; REP(d,0,u){ if(d==0) res+=dfs(i-1,d,one,zero+(one?1:0),e&&d==u); else res+=dfs(i-1,d,one+1,zero,e&&d==u); } return e?res:f[i][s][one][zero]=res; } ll F(ll n) { MS0(num); int len=0; while(n){ num[len++]=n%2; n>>=1; } MS1(f); return dfs(len-1,0,0,0,1); } int main() { //freopen("in.txt","r",stdin); while(cin>>L>>R){ cout<<F(R)-F(L-1)<<endl; } return 0; }
F题:
求[L,R]中平衡数的个数。平衡数即以某位作为支点,两边数的位置作为权值,距离支点的距离为力臂,天平平衡的数。如4139,支点为3,4*2+1*1=9*1,是平衡数。
做完这题后对dfs(i,s,e)的模板有了更深的理解,中间的s并不只是第i+1位的数,而是第i+1位的状态,这个状态可以是一个变量也可以是多个变量,可以是第i+1位的数,也可以是第i+1位的某一状态特征。
如本题的s为:(sum,pos),故f[i][sum][pos]。
解决本题还需首先明确一个事实,每个平衡数有且只有一个支点,但由于计算是不考虑前导0,所以会多算了00,000,0000等,因此最终答案需减去len-1。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); ll L,R; int num[30]; const ll zero=2100; ll f[30][4200][30]; ll dfs(int i,int sum,int pos,bool e) { if(i==-1) return sum==zero; if(sum<zero) return 0; ///这个剪枝并没有多大效果 if(!e&&~f[i][sum][pos]) return f[i][sum][pos]; ll res=0; int u=e?num[i]:9; REP(d,0,u){ res+=dfs(i-1,sum+(i-pos)*d,pos,e&&d==u); } return e?res:f[i][sum][pos]=res; } ll F(ll n) { MS0(num); int len=0; while(n){ num[len++]=n%10; n/=10; } MS1(f); ll res=0; REP(i,0,len-1) res+=dfs(len-1,zero,i,1); return res-(len-1); } int main() { freopen("in.txt","r",stdin); DRI(T); while(T--){ cin>>L>>R; cout<<F(R)-F(L-1)<<endl; } return 0; }
xdoj1076:
http://acm.xidian.edu.cn/problem.php?id=1076
数位dp,水题。注意前导0的情况,即0000135,处理方法是判断s和d是否都为0,因为s==0&&d==1,3,5可能符合条件,而s==1,3,5&&d==0一定不符合条件。
注意unsigned long long .
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll unsigned long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); char str[52]; int num[52]; ll f[52][20]; ll dfs(int i,int s,bool e) { if(i==-1) return 1; if(!e&&~f[i][s]) return f[i][s]; ll res=0; int u=e?num[i]:9; REP(d,0,u){ if(d==1||d==3||d==5) res+=dfs(i-1,d,e&&u==d); else if(d==0&&s==0) res+=dfs(i-1,d,e&&u==d); } return e?res:f[i][s]=res; } int main() { freopen("in.txt","r",stdin); while(~RS(str)){ int len=strlen(str); MS0(num); REP(i,0,len-1) num[i]=str[len-1-i]-'0'; MS1(f); printf("%llu ",dfs(len-1,0,1)-1); } return 0; }
##### 以上几个题的代码中每次计算F函数时都对f进行了初始化,然而完全没有必要!!!因为f的值和n并没有什么关系,并不需要每次都初始化,而每次都初始化大大增加了复杂度。比如接下来的这道题就TLE了!!!!!!!!!!!!#############
A题:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70324#problem/A
求[L,R]中符合条件的数的个数,条件为:一个数n,能被它的每一位非0的数整除。
思路:能被n的每一位整除即能被它所有位的lcm整除,因此最后判断条件为n%lcm,而n太大不能作为状态,然而lcm(1,2,..,9)=2520,lcm一定是2520的约数,因此n%lcm=n%(k*lcm)%lcm=n%2520%lcm。而n=(...((a5*10+a4)*10+a3)...),根据同余模定理,状态存2520的余数即可,最后在判断能否被lcm整除。
然而这时f[i][mod][lcm],第二维和第三维长度都是2520,第一维19,显然超内存了,但由于1到9的lcm的所有可能只有48种,离散化即可,因为lcm一定是2520的约数。
这样就变成了f[i][mod][id]。接着就是f数组不用每次都初始化。。。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll unsigned long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); ll L,R; int num[30]; const int MOD=2520; ll f[21][2521][50]; int lcm[50],cnt; //map<int,int> ID; int ID[2530]; void Init() { MS0(ID); cnt=0; REP(i,1,MOD){ if(MOD%i==0) lcm[cnt++]=i,ID[i]=cnt-1; } } ll LCM(ll a,ll b) { return a/__gcd(a,b)*b; } ll dfs(int i,int mod,int id,bool e) { if(i==-1) return mod%lcm[id]==0; if(!e&&~f[i][mod][id]) return f[i][mod][id]; ll res=0; int u=e?num[i]:9; REP(d,0,u){ if(d==0) res+=dfs(i-1,(mod*10)%MOD,id,e&&d==u); else res+=dfs(i-1,(mod*10+d)%MOD,ID[LCM(lcm[id],d)],e&&d==u); } return e?res:f[i][mod][id]=res; } ll F(ll n) { MS0(num); int len=0; while(n){ num[len++]=n%10; n/=10; } return dfs(len-1,0,ID[1],1); } int main() { freopen("in.txt","r",stdin); Init(); DRI(T); MS1(f); while(T--){ scanf("%I64u%I64u",&L,&R); printf("%I64u ",F(R)-F(L-1)); } return 0; }
G题:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70324#problem/G
求[0,N]中含有"13"且能被13整除的数的个数。
有了上一道题的经验,这题直接秒啊。。。竟成水题了。。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); ll n; int num[30]; ll f[30][12][15][2]; ll dfs(int i,int s,int mod,int has,bool e) { if(i==-1) return mod==0&&has; if(!e&&~f[i][s][mod][has]) return f[i][s][mod][has]; ll res=0; int u=e?num[i]:9; REP(d,0,u){ if(s==1&&d==3) res+=dfs(i-1,d,(mod*10+d)%13,1,e&&d==u); else res+=dfs(i-1,d,(mod*10+d)%13,has,e&&d==u); } return e?res:f[i][s][mod][has]=res; } ll F(ll n) { MS0(num); int len=0; while(n){ num[len++]=n%10; n/=10; } return dfs(len-1,0,0,0,1); } int main() { freopen("in.txt","r",stdin); MS1(f); while(cin>>n){ cout<<F(n)<<endl; } return 0; }
H题:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70324#problem/H
给定函数F(x)。输入A,B。求[0,B]中的F(x)不超过F(A)的x的个数。
F(x)的范围是20000左右,f[i][A][sum]这样会超内存,而f[i][sum]则需每次根据A初始化,注意到判断条件是sum<A,因此只需存A-sum即可,这样f就变成f[i][A-sum]。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); ll A,B; int num[11]; ll f[11][21000]; ll dfs(int i,int cha,bool e) { if(i==-1) return cha>=0; if(cha<0) return 0; if(!e&&~f[i][cha]) return f[i][cha]; ll res=0; int u=e?num[i]:9; REP(d,0,u){ res+=dfs(i-1,cha-d*(1<<i),e&&d==u); } return e?res:f[i][cha]=res; } ll F(ll n) { int len=0; while(n){ num[len++]=n%10; n/=10; } return dfs(len-1,A,1); } ll bin(ll n) { ll res=0,t=0; while(n){ res+=(n%10)*(1<<t); n/=10;t++; } return res; } int main() { freopen("in.txt","r",stdin); DRI(T); int casen=1; MS1(f); while(T--){ scanf("%I64d%I64d",&A,&B); A=bin(A); printf("Case #%d: %I64d ",casen++,F(B)); } return 0; }
H题:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70324#problem/J
求[L,R]中的与7无关的数的平方和。
维护三个数,个数cnt,和sum,平方和sqsum。
维护cnt和sum的目的是推出sqsum。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll unsigned long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); const ll MOD=1000000000+7; ll L,R; int num[20]; struct Node { ll cnt,sum,sqsum; }; Node f[20][10][10]; ll p[20]; ll qpow(ll n,ll k,ll p) { ll res=1; while(k){ if(k&1) res=((res%p)*(n%p))%p; n=((n%p)*(n%p))%p; k>>=1; } return res; } Node dfs(int i,int mod1,int mod2,int e) { if(i==-1){ if(mod1&&mod2) return {1,0,0}; return {0,0,0}; } if(!e&&f[i][mod1][mod2].cnt!=-1) return f[i][mod1][mod2]; Node res={0,0,0}; int u=e?num[i]:9; REP(d,0,u){ if(d==7) continue; Node tmp=dfs(i-1,(mod1+d)%7,(mod2*10+d)%7,e&&d==u); res.cnt+=tmp.cnt; res.cnt%=MOD; res.sum=(res.sum%MOD+tmp.sum%MOD+((tmp.cnt%MOD)*(d*p[i])%MOD)%MOD)%MOD; res.sqsum=(res.sqsum%MOD+tmp.sqsum%MOD+(((2*d*p[i])%MOD)*tmp.sum)%MOD+(tmp.cnt%MOD)*qpow(d*p[i],2,MOD))%MOD; } return e?res:f[i][mod1][mod2]=res; } ll F(ll n) { int len=0; while(n){ num[len++]=n%10; n/=10; } return dfs(len-1,0,0,1).sqsum%MOD; } void Init() { MS0(f); REP(i,0,19){ REP(j,0,9){ REP(k,0,9) f[i][j][k].cnt=-1; } } MS0(p); REP(i,0,19){ p[i]=qpow(10,i,MOD); } } int main() { freopen("in.txt","r",stdin); Init(); DRI(T); while(T--){ cin>>L>>R; cout<<(F(R)+MOD-F(L-1))%MOD<<endl; } return 0; }
K题:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70324#problem/K
求[L,R]中奇数出现偶数次,偶数出现奇数次的数的个数。
f[i][has][3][3][3][3][3][3][3][3][3][3]:第一维表示位数,has表示是否已经出现了非0位,后面的表示0~9是否出现和出现次数奇偶。
可以把后面的9维状态按三进制压缩成一个整数,变成一维。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll unsigned long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); ll L,R; int num[22]; ll f[22][2][3][3][3][3][3][3][3][3][3][3]; ll dfs(int i,int has,int t0,int t1,int t2,int t3,int t4,int t5,int t6,int t7,int t8,int t9,bool e) { int tt[12]={t0,t1,t2,t3,t4,t5,t6,t7,t8,t9}; if(i==-1){ REP(k,0,9){ if(tt[k]!=0&&(tt[k]&1)==(k&1)) return 0; } return 1; } if(!e&&~f[i][has][t0][t1][t2][t3][t4][t5][t6][t7][t8][t9]) return f[i][has][t0][t1][t2][t3][t4][t5][t6][t7][t8][t9]; ll res=0; int u=e?num[i]:9; int nt=0; REP(d,0,u){ if(d==0){ if(has){ if(t0==0||t0==2) nt=1; else nt=2; } else nt=0; res+=dfs(i-1,has,nt,t1,t2,t3,t4,t5,t6,t7,t8,t9,e&&d==u); } else{ int pt=tt[d]; if(tt[d]==0||tt[d]==2) tt[d]=1; else tt[d]=2; res+=dfs(i-1,1,tt[0],tt[1],tt[2],tt[3],tt[4],tt[5],tt[6],tt[7],tt[8],tt[9],e&&d==u); tt[d]=pt; } } return e?res:f[i][has][t0][t1][t2][t3][t4][t5][t6][t7][t8][t9]=res; } ll F(ll n) { int len=0; while(n){ num[len++]=n%10; n/=10; } return dfs(len-1,0,0,0,0,0,0,0,0,0,0,0,1); } int main() { freopen("in.txt","r",stdin); DRI(T); MS1(f); while(T--){ cin>>L>>R; cout<<F(R)-F(L-1)<<endl; } return 0; }
随便找了到水题:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=80070#problem/R
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<set> #include<map> #include<string> #include<math.h> #include<cctype> #define ll long long #define REP(i,a,b) for(int (i)=(a);(i)<=(b);(i)++) #define REPP(i,a,b,t) for(int (i)=(a);(i)<=(b);(i)+=(t)) #define rep(i,a,b) for(int (i)=(a);(i)>=(b);(i)--) #define repp(i,a,b,t) for(int (i)=(a);(i)>=(b);(i)-=(t)) #define PII pair<int,int> #define fst first #define snd second #define MP make_pair #define PB push_back #define RI(x) scanf("%d",&(x)) #define RII(x,y) scanf("%d%d",&(x),&(y)) #define RIII(x,y,z) scanf("%d%d%d",&(x),&(y),&(z)) #define DRI(x) int (x);scanf("%d",&(x)) #define DRII(x,y) int (x),(y);scanf("%d%d",&(x),&(y)) #define DRIII(x,y,z) int (x),(y),(z);scanf("%d%d%d",&(x),&(y),&(z)) #define RS(x) scanf("%s",x) #define RSS(x,y) scanf("%s%s",x,y) #define DRS(x) char x[maxn];scanf("%s",x) #define DRSS(x,y) char x[maxn],y[maxn];scanf("%s%s",x,y) #define MS0(a) memset((a),0,sizeof((a))) #define MS1(a) memset((a),-1,sizeof((a))) #define MS(a,b) memset((a),(b),sizeof((a))) #define ALL(v) v.begin(),v.end() #define SZ(v) (int)(v).size() using namespace std; const int maxn=1000100; const int INF=(1<<29); const double EPS=0.0000000001; const double Pi=acos(-1.0); ll L,R; int num[20]; ll f[20][2][12]; ll dfs(int i,int has,int s,bool e) { if(i==-1) return 1; if(!e&&~f[i][has][s]) return f[i][has][s]; ll res=0; int u=e?num[i]:9; REP(d,0,u){ if(has){ if(abs(s-d)>=2) res+=dfs(i-1,has,d,e&&d==u); } else res+=dfs(i-1,d?1:0,d,e&&d==u); } return e?res:f[i][has][s]=res; } ll F(int n) { int len=0; while(n){ num[len++]=n%10; n/=10; } return dfs(len-1,0,0,1); } int main() { freopen("in.txt","r",stdin); MS1(f); while(cin>>L>>R){ cout<<F(R)-F(L-1)<<endl; } return 0; }
=====================================================================================================================
数位dp暂时告一段落了,剩下两道一道要在数位dp上套lis,另一道是AC自动机+数位dp。。。。等学了AC自动机再回来补。
下一专题:激动人心的线段树!!!