地址:https://www.nowcoder.com/acm/contest/190/D
思路:数位DP+二分。利用数位DP可以求出从1到n的满足条件的个数,而对于求具体的数字,则可以用二分查找来求解
dp[i][j][k]: 前i位余数为j,是否有7的个数
Code:
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
LL n,m;
int a[20];
LL dp[20][10][2];
LL Find(LL p);
LL DFS(int k,int mod,int boo,int bo);
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>m){
memset(dp,-1,sizeof(dp));
LL l=n,r=1e14,t=Find(n);
while(l<=r){
LL h=(l+r)/2;
if(Find(h)-t>=m) r=h-1;
else l=h+1;
}
cout<<l<<endl;
}
return 0;
}
LL Find(LL p)
{
int pre=0;
while(p){
a[pre++]=p%10;
p/=10;
}
return DFS(pre-1,0,0,1);
}
LL DFS(int k,int mod,int boo,int bo) //第k位,余数mod,boo是否有7,bo是否为p
{
LL ans=0;
if(k==-1) ans=(!mod)||boo;
else if(dp[k][mod][boo]!=-1&&!bo) ans=dp[k][mod][boo];
else{
int pre=bo?a[k]:9;
for(int i=0;i<=pre;++i)
ans+=DFS(k-1,(mod*10+i)%7,boo||i==7,bo&&i==a[k]);
if(!bo) dp[k][mod][boo]=ans;
}
return ans;
}