您的位置:首页 > 其它

CodeChef FAVNUM FavouriteNumbers(AC自动机+数位dp+二分答案)

2018-02-26 15:20 477 查看
FavouriteNumbers Problem Code:FAVNUM

Chef likes numbers and number theory, weall know that. There areN digit strings that he particularly likes. Helikes them so much that he defines some numbers to bebeautiful numbersbased
on these digit strings.
Beautiful numbers are those numberswhose decimal representation containsat least one of chef's favoritedigit strings as a substring. Your task is to calculate theKthsmallest
number amongst the beautiful numbers in the range fromL to
R
(both inclusive). If the number of beautiful numbers betweenL and
Ris less than K, then output "no such number".

Input

In the first line of input there will beintegersL,
R, K and N. ThenN lines follow.Each line will contain a single string of decimal digits.

Output

Output one integer - the solution to theproblem described above or a string "no such number" if thereis no such number.

Constraints

·       1<=L<=R<=10^18
·       1<=K<=R-L+1
·       1<=N<=62
·       1<=The length of any Chef's favourite digit string<=18.Each string begins with a nonzero digit.

Example

Input:
1 1000000000 4 2
62
63
Output:
163
Input:
1 1 1 1
2
Output:
no such number
Input:
1 1000 15 2
6
22
Output:

67

        好久没有写数位dp了,着实快忘记怎么写了……
        大致题意是,给你一些幸运数字,然后问你在一个区间内的第k大的,含有幸运数字的数是哪一个数字。

        其实做法也很简单,这种类型的题目一看就知道是数位dp,然后求第k大,肯定是二分枚举这个数字,然后每次数位dp计算小于等于这个数字的范围内有多少个数字满足条件。关键就在于如何判定这个数字是否包含了幸运数字。而AC自动机正好可以解决这个问题,我们把所有的幸运数字加入到AC自动机中,然后我们同样在AC自动机上面dp。dp[len][pos][flag]表示当前长度为len,走到AC自动机上pos点的时候取幸运数字状态为flag(是或否取到)的方案数。那么我们显然可以有转移方程:dp[len][pos][flag]=Σ
dp[len-1][ch][flag || AC.T[ch].cnt],其中ch为pos的某一个后继节点。意思是,如果到下一个节点能够组成一个幸运数字,那么flag的状态就要相应改变。之后,按照普通数位dp的套路那样,记忆化搜索转移即可。
        具体见代码:
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define LL long long
#define mod 20090717
#define N 1010
using namespace std;

LL dp[20][1310][2];
int num[20];

struct AC_automation
{
struct node{int fail,cnt,ch[10];} T[1210];
int tot,root;void init(){tot=0;root=newnode();}

int newnode()
{
for(int i=0;i<10;i++) T[tot].ch[i]=0;
T[tot].fail=T[tot].cnt=0; return tot++;
}

void ins(char* x)
{
int o=root;
for(int k=0;x[k];k++)
{
int c=x[k]-'0';
if(!T[o].ch[c]) T[o].ch[c]=newnode();
o=T[o].ch[c];
}
T[o].cnt=1;
}

void get_fail()
{
queue<int> q;
q.push(root);
while(!q.empty())
{
int o=q.front();
T[o].cnt|=T[T[o].fail].cnt;
for(int i=0;i<10;i++)
{
if (!T[o].ch[i])
{
T[o].ch[i]=T[T[o].fail].ch[i];
continue;
}
if (o!=root)
{
int fa=T[o].fail;
while(fa&&!T[fa].ch[i]) fa=T[fa].fail;
T[T[o].ch[i]].fail=T[fa].ch[i];
} else T[T[o].ch[i]].fail=root;
q.push(T[o].ch[i]);
} q.pop();
}
}

} AC;

LL dfs(int len,int pos,bool flag,bool lim)
{
if (len<=0) return flag;
if (!lim&&dp[len][pos][flag]>=0) return dp[len][pos][flag];
int up=lim?num[len]:9; LL res=0;
for(int i=0;i<=up;i++)
{
int nxt=AC.T[pos].ch[i];
res+=dfs(len-1,nxt,flag||AC.T[nxt].cnt,lim&&i==up);
}
if (!lim) dp[len][pos][flag]=res;
return res;
}

LL cal(LL x)
{
int len=0;
while(x)
{
num[++len]=x%10;
x/=10;
}
return dfs(len,0,0,1);
}

int main()
{
char s[20]; LL n,l,r,k;
cin>>l>>r>>k>>n;
AC.init();
while(n--)
{
scanf("%s",s);
AC.ins(s);
}
AC.get_fail();
memset(dp,-1,sizeof(dp));
LL tmp=cal(l-1),mid,ans=0;
while(l<=r)
{
mid=(l+r)>>1;
if (cal(mid)-tmp>=k) r=mid-1,ans=mid;
else l=mid+1;
}
if (ans) cout<<ans<<endl;
else puts("no such number");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: