题目大意:
给你一段区间,让你求满足下列两个条件时的数的个数。
1、至少有 3 个相邻相同数字 (即 111 、1111 、222 等)
2、不能同时出现 8 与 4 。
给定的区段 [L,R] 中 ,L 与 R 的数值范围为:1010 ≤ L ≤ R < 1011
分析:
1、用 q 与 w 标记 8 是否出现 ,4 是否出现。
2、为了得知是否有连续三个相等,故还需要 ppre 表示前两位中的第一位数位上的数,pre 表示前一位数位上的数,还需要再加 flag 标记是否当前已满足 ppre == pre == i
3、剩下的就是前导零与位数限制标记了 (即 lead 与 limit )
故 dp 需要 5 维,pos、ppre、pre、flag、q、w ,然后直接记忆化即可。
代码如下:
#include<iostream> #include<algorithm> #include<string.h> using namespace std; typedef long long ll; ll L,R; ll a[15]; ll dp[15][15][15][2][2][2]; ll dfs(int pos,int ppre,int pre,bool flag,bool q,bool w,bool lead,bool limit){ if(pos==0) return flag&&(!(q&&w)); if(!limit&&dp[pos][ppre][pre][flag][q][w]!=-1) return dp[pos][ppre][pre][flag][q][w]; int up=limit?a[pos]:9; ll res=0; for(int i=0;i<=up;i++){ if(lead&&i==0) res+=dfs(pos-1,-1,-1,false,false,false,true,limit&&i==a[pos]); else res+=dfs(pos-1,pre,i,(ppre==pre&&pre==i)||flag,(q||i==4),(w||i==8),false,limit&&i==a[pos]); } if(!limit) dp[pos][ppre][pre][flag][q][w]=res; return res; } ll solve(ll x) { int pos=0; while(x){ a[++pos]=x%10; x/=10; } return dfs(pos,-1,-1,0,false,false,true,true); } int main() { //freopen("test.in","r",stdin); //freopen("test.out","w",stdout); memset(dp,-1,sizeof(dp)); scanf("%lld%lld",&L,&R); printf("%lld\n",solve(R)-solve(L-1) ); }
来源:https://www.cnblogs.com/Absofuckinglutely/p/11430526.html