数位dp 专题

数位dp 专题

先来模板:

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;
}
View Code

 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的题。。。

#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;
}
View Code

 D题:

求[0,N]中含有49的数的个数。

先求不含49的个数k,注意总个数是N+1,(区间为[0,N],0也算一个)。

注意用unsigned long long。

#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;
}
View Code

 E题:

求[L,R]中二进制表示中0的个数比1的个数多或等的数的个数。

f[i][s][one][zero]:i表示当前位数,s,one,zero分别表示之前的数字,之前的1的个数,之前的0的个数(不含前导0)。

#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;
}
View Code

 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。

#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;
}
View Code

 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 .

#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;
}
View Code

 ##### 以上几个题的代码中每次计算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数组不用每次都初始化。。。。。

#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;
}
View Code

 G题:

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70324#problem/G

求[0,N]中含有"13"且能被13整除的数的个数。

有了上一道题的经验,这题直接秒啊。。。竟成水题了。。。

#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;
}
View Code

 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]。

#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;
}
View Code

 H题:

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=70324#problem/J

求[L,R]中的与7无关的数的平方和。

维护三个数,个数cnt,和sum,平方和sqsum。

维护cnt和sum的目的是推出sqsum。

#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;
}
View Code

 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维状态按三进制压缩成一个整数,变成一维。

#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;
}
View Code

 随便找了到水题:

http://acm.hust.edu.cn/vjudge/contest/view.action?cid=80070#problem/R

#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;
}
View Code

 =====================================================================================================================

数位dp暂时告一段落了,剩下两道一道要在数位dp上套lis,另一道是AC自动机+数位dp。。。。等学了AC自动机再回来补。

下一专题:激动人心的线段树!!!

没有AC不了的题,只有不努力的ACMER!
原文地址:https://www.cnblogs.com/--560/p/4690129.html