zoukankan      html  css  js  c++  java
  • BZOJ 4521 [Cqoi2016]* 数位DP

    这题也就是一道数位DP裸题.

    (尽管我写得很挫).

    别看我代码.

    (尽管注释很详细).

    终于破除了我数位DP永远写不对的魔咒.

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<string>
    #include<cmath>
    #include<ctime>
    #include<algorithm>
    #include<map>
    #include<set>
    #include<queue>
    #include<iomanip>
    using namespace std;
    #define ll long long
    #define db double 
    #define up(i,j,n) for(ll i=j;i<=n;i++)
    #define pii pair<ll,ll>
    #define uint unsigned ll
    #define FILE "dealing"
    ll read(){
    	ll x=0,f=1,ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	return x*f;
    }
    template<class T> bool cmax(T& a,T b){return a<b?a=b,true:false;}
    template<class T> bool cmin(T& a,T b){return a>b?a=b,true:false;}
    const int maxn=1010000;
    ll f[13][11][2][2][2][2];
    ll g[13][11][2][2][2][2][2];
    ll n,m;
    int w[20],r[20];
    // pos la ch lianx 8  4 33 是否卡上界
    int check(ll n){
    	int f1=0,f2=0;
    	r[0]=0;
    	while(n){r[++r[0]]=n%10;n/=10;}
    	up(i,1,11){
    		if(r[i]==4)f1=1;
    		if(r[i]==8)f2=1;
    	}
    	if(f1&&f2)return 0;
    	up(i,1,9){
    		if(r[i]==r[i+1]&&r[i+1]==r[i+2])return 1;
    	}
    	return 0;
    }//        位置  最后字符 是否连续  8     4    是否有过三联 是否卡上界
    ll dfs(int pos,int last,int f1,int f2,int f3,int f4,int f5){
    	if(pos==0){
    		if(f4)return 1;
    		return 0;
    	}
    	if(!f5){
    		ll ans=0;
    		for(int j=0;j<=9;j++){//最前数字
    			for(int k=0;k<=1;k++){//是否连续
    				for(int w=0;w<=1;w++){//8
    					for(int t=0;t<=1;t++){//4
    						for(int p=0;p<=1;p++){//是否三联过
    							if(w&&f3)continue;
    							if(t&&f2)continue;
    							if(!p&&!f4&&!(last==j&&(k||f1)))continue;
    							ans+=f[pos][j][k][w][t][p];
    						}
    					}
    				}
    			}
    		}
    		return ans;
    	}
    	else {//卡上界
    		ll ans=0;
    		int flag1,flag2,flag3,flag4;
    		for(int j=0;j<=w[pos];j++){//当前数字
    			if(j==4&&f2)continue;
    			if(j==8&&f3)continue;
    			flag1=flag2=flag3=flag4=0;
    			if(j==8||f2)flag1=1;if(j==4||f3)flag2=1;
    			if((j==last&&f1)||f4)flag3=1;
    			if(j==last)flag4=1;
    			ans+=dfs(pos-1,j,flag4,flag1,flag2,flag3,j==w[pos]);
    		}
    		return ans;
    	}
    }
    ll solve(ll n){
    	memset(w,0,sizeof(w));ll p=n;
    	while(n){
    		w[++w[0]]=n%10;
    		n/=10;
    	}
    	ll ans=0;
    	up(i,1,w[11]){
    		if(i!=4&&i!=8)ans+=dfs(10,i,0,0,0,0,i==w[11]);
    		if(i==4)ans+=dfs(10,i,0,0,1,0,i==w[11]);
    		if(i==8)ans+=dfs(10,i,0,1,0,0,i==w[11]);
    	}
    	return ans;
    }
    int main(){
    	freopen(FILE".in","r",stdin);
    	freopen(FILE".out","w",stdout);
    	up(i,0,9){
    		if(i!=8&&i!=4)f[1][i][0][0][0][0]=1;
    		if(i==8)f[1][i][0][1][0][0]=1;
    		if(i==4)f[1][i][0][0][1][0]=1;
    	}
    	int f1,f2,f3,f4;
    	for(int i=1;i<=11;i++){//位数
    		for(int j=0;j<=9;j++){//枚举当前最前方的数字
    			for(int k=0;k<=1;k++){//枚举这个数字是否连续两次以上
    				for(int w=0;w<=1;w++){//枚举8是否出现过
    					for(int t=0;t<=1;t++){//枚举4是否出现过
    						for(int p=0;p<=1;p++){//枚举以前是否出现过三个以上的情况
    							if(f[i][j][k][w][t][p]==0)continue;
    							for(int y=0;y<=9;y++){//枚举转移的方向
    								if(y==4&&w)continue;
    								if(y==8&&t)continue;
    								f1=f2=f3=f4=0;
    								if(y==8||w)f1=1;if(y==4||t)f2=1;
    								if((j==y&&k)||p)f3=1;
    								if(j==y)f4=1;
    								f[i+1][y][f4][f1][f2][f3]+=f[i][j][k][w][t][p];
    							}
    						}
    					}
    				}
    			}
    		}
    	}
    	n=read(),m=read();
    	printf("%lld
    ",solve(m)-solve(n-1));
    	return 0;
    }
    

      

  • 相关阅读:
    第十六周总结
    第十五周学习进度
    输出最长字符串链
    第二阶段冲刺10
    第二阶段冲刺09
    第二阶段冲刺08
    输入法评价
    第十四周进度总结
    collections模块
    shutil模块(了解)
  • 原文地址:https://www.cnblogs.com/chadinblog/p/6550516.html
Copyright © 2011-2022 走看看