题意
题目就是说让我们在l到r的数字中求得有多少个连续k为不相同的数
1≤L≤R≤1e18
2≤K≤5
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
分析
直接枚举必然超时 考虑数位dp
由于k最大到5 所以我们可以记录前四位的大小 通过一个check函数去判断是否存在相同的数
也就是说 状态转移发生在前四位对应的数字大小的情况下
我们开一个dp[pos][p1][p2][p3][p4]记录在pos下前四位分别是p1,p2,p3,p4的符合条件的数的个数
然后每次搞完后记录下来(没有限制) 我们的dp数组中只记录没有限制的数 如果有限制就不记录只是求和
如何判断前四位是否与本位相同 我们可以把前导0用10表示 如果前面的位数是10表示前面的数是0
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll ans,l,r,k,dp[20][11][11][11][11],d[20],dig;
bool check(int p4,int p3,int p2,int p1,int x){if(k==2&&p1!=10)return x!=p1;else if(k==3)return (x!=p1&&x!=p2);else if(k==4)return (x!=p1&&x!=p2&&x!=p3);else return (x!=p1&&x!=p2&&x!=p3&&x!=p4);
}
ll DP(int pos,int p4,int p3,int p2,int p1,bool limit){if(pos==0){return p1!=10;}if(!limit&&~dp[pos][p4][p3][p2][p1])return dp[pos][p4][p3][p2][p1];int up = limit?d[pos]:9;ll a=0;for(int i=0;i<=up;i++){if(p1==10&&i==0)a+=DP(pos-1,10,10,10,10,limit&&i==up);else if(check(p4,p3,p2,p1,i))a+=DP(pos-1,p3,p2,p1,i,limit&&i==up);}if(!limit)dp[pos][p4][p3][p2][p1]=a;return a;
}
ll solve(ll x)
{dig=0;while(x){d[++dig]=x%10;x/=10;}return DP(dig,10,10,10,10,1);
}
int main()
{while(~scanf("%lld%lld%lld",&l,&r,&k)){memset(dp,-1,sizeof(dp));printf("%lld\n",solve(r)-solve(l-1));}return 0;
}