• bzoj 4521: [Cqoi2016]*


    感觉get到了一种数位dp的新姿势,加一位表示当前要填的数有没有限制(感觉以前的写法都太蠢了).

    这么写有两个地方要注意:

    1.每dp到一位时需要f[i][初始状态]++,相当于这位前都是前导零(这道题我把前两位填了两个10作为初始状态)。

    2.因为有了1,所以初始状态后的第一位不能填0,需要特判

    f[i][j][k][l][p][q][o]表示填到第几位,上上位和上位分别是什么,4,8是否出现过,三个连续的是否出现过,以及当前位是否有限制。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    ll pw[100];
    ll f[20][11][11][2][2][2][2];
    // 位数 上位 这位 4 8 出现0/1 限制0/1 
    ll solve(ll x)
    {
    	pw[0]=1;
    	for(int i=1;i<=12;i++)pw[i]=pw[i-1]*10;
    	int pos;
    	for(int i=0;i<=12;i++)if(x>=pw[i])pos=i+1;
    	memset(f,0,sizeof(f));
    	f[0][10][10][0][0][0][1]=1;
    	for(int i=1;i<=pos;i++)
    	{
    		int ks=x/pw[pos-i]%10;
    	    f[i][10][10][0][0][0][0]=1;
    		// 刷表
    		for(int j=0;j<=10;j++)
    		{
    			for(int k=0;k<=10;k++)
    			{
    				for(int l=0;l<=1;l++)
    				{
    					for(int p=0;p<=1;p++)
    					{
    						// 这位
    						for(int q=0;q<=9;q++)
    						{
    							if(j==10&&k==10&q==0)continue;
    							bool b1=0,c1=0,d1=0;
    							if(j==k&&j==q)b1=1;
    							if(q==4)c1=1;
    							if(q==8)d1=1;
    							f[i][k][q][l|c1][p|d1][1][0]+=f[i-1][j][k][l][p][1][0];
    							f[i][k][q][l|c1][p|d1][b1][0]+=f[i-1][j][k][l][p][0][0];
    						}
    						for(int q=0;q<=ks;q++)
    						{
    							if(j==10&&k==10&q==0)continue;
    							bool b1=0,c1=0,d1=0;
    							if(j==k&&j==q)b1=1;
    							if(q==4)c1=1;
    							if(q==8)d1=1;
    							if(q!=ks)
    							{
    								f[i][k][q][l|c1][p|d1][1][0]+=f[i-1][j][k][l][p][1][1];
    								f[i][k][q][l|c1][p|d1][b1][0]+=f[i-1][j][k][l][p][0][1];
    							}
    							else 
    							{
    								f[i][k][q][l|c1][p|d1][1][1]+=f[i-1][j][k][l][p][1][1];
    								f[i][k][q][l|c1][p|d1][b1][1]+=f[i-1][j][k][l][p][0][1];
    							}
    						}
    					}
    				}
    			}
    		}
    	}
    	ll ans=0;
    	for(int i=0;i<=9;i++)for(int j=0;j<=9;j++)for(int k=0;k<=1;k++)for(int l=0;l<=1;l++)for(int s=0;s<=1;s++)
    	{
    		if(k&&l)continue;
    		ans+=f[pos][i][j][k][l][1][s];
    	}
    	return ans;
    }
    ll l,r;
    int main()
    {
    	scanf("%lld%lld",&l,&r);
    	printf("%lld
    ",solve(r)-solve(l-1));
    	return 0;
    }
    

      

  • 相关阅读:
    Codeforces Round #311 (Div. 2)题解
    firefox 被劫持hao123 主页
    国有航空为啥“放下身段”读春秋?
    ORACLE中常见SET指令
    最大概率法分词及性能測试
    怎样利用JDBC连接并操作Oracle数据库
    hdu5240
    代码调试过程中easy遇到的问题
    最简单的基于FFmpeg的AVDevice样例(读取摄像头)
    FPGA 功耗结构设计
  • 原文地址:https://www.cnblogs.com/ezyzy/p/6786381.html
Copyright © 2020-2023  润新知