省选2016系列…CQOI d1t3
显然的数位dp,状态也比较好想,dp[i][j][k][a][b][c]表示前i位,是否已经小于原数,当前后两个数是j,k,是否出现4,8,是否已经出现连续的3个。(有点复杂…>_<…)
省选数据是厉害…有三个数据的l都是10000000000,因为我默认他的位数是11位,l-1一下就挂飞了…大家引以为鉴…
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
//by:MirrorGray
using namespace std;
const int N=13;
ll dp[N][2][N][N][4][2];
int g(int a,int b){
return ((a==8)<<1)|(a==4)|((b==8)<<1)|(b==4);
}
ll solve(ll x){
static int s[N];int top=0;
while(x)s[top++]=x%10,x/=10;
reverse(s,s+top);
memset(dp,0,sizeof(dp));
int ap=g(s[0],s[1]),fg=0;
dp[2][0][s[0]][s[1]][ap][fg]=1;
for(int i=1;i<=s[0];i++)for(int j=0;j<(i==s[0]?s[1]:10);j++)dp[2][1][i][j][g(i,j)][0]=1;
for(int i=2;i<11;i++){
ap|=g(s[i],s[i]);fg|=((s[i]==s[i-1])&&(s[i-1]==s[i-2]));
if(fg!=3)dp[i+1][0][s[i-1]][s[i]][ap][fg]=1;
for(int j=0;j<10;j++)
for(int k=0;k<10;k++)
for(int a=0;a<3;a++){
for(int b=0;b<10;b++){
int t1=a|g(b,b),t2=(b==k)&&(k==j);
if(t1==3)continue;
dp[i+1][1][k][b][t1][1]+=(b<s[i])*dp[i][0][j][k][a][1]+dp[i][1][j][k][a][1];
dp[i+1][1][k][b][t1][t2]+=(b<s[i])*dp[i][0][j][k][a][0]+dp[i][1][j][k][a][0];
}
}
}
ll ret=0;
for(int j=0;j<10;j++)
for(int k=0;k<10;k++)
for(int a=0;a<3;a++)
for(int b=0;b<2;b++)ret+=dp[11][b][j][k][a][1];
return ret;//+233;//(wu..)
}
int main(){
ll l,r;scanf("%lld%lld",&l,&r);
if(l==10000000000)printf("%lld\n",solve(r));//是厉害…
else printf("%lld\n",solve(r)-solve(l-1));
return 0;
}
//orz Poker_face
//祈愿heoi2016一切平安…>_<…