ZOJ 3891 K-hash 后缀自动机

70 篇文章 0 订阅


后缀自动机求不同的串,然后DP.....


K-hash

Time Limit: 2 Seconds       Memory Limit: 131072 KB

K-hash is a simple string hash function. It encodes a string Sconsist of digit characters into a K-dimensional vector (h0h1h2,... , hK-1). If a nonnegative number xoccurs in S, then we call x is S-holded. And hi is the number of nonnegative numbers which are S-holded and congruent with i modulo K, for i from 0 to K-1.

For example, S is "22014" and K=3. There are 12 nonnegative numbers are "22014"-holded: 0, 1, 2, 4, 14, 20, 22, 201, 220, 2014, 2201 and 22014. And three of them, 0, 201 and 22014, are congruent with 0 modulo K, so h0=3. Similarly, h1=5 (1, 4, 22, 220 and 2014 are congruent with 1 modulo 3), h2=4(2, 14, 20 and 2201 are congruent with 2 modulo 3). So the 3-hash of "22014" is (3, 5, 4).

Please calculate the K-hash value of the given string S.

Input

There are multiple cases. Each case is a string S and a integer number K. (S is a string consist of '0', '1', '2', ... , '9' , 0< |S| ≤ 50000, 0< K≤ 32)

Output

For each case, print K numbers (h0h1h2,... , hK-1 ) in one line.

Sample Input
123456789 10
10203040506007 13
12345678987654321 2
112123123412345123456123456712345678123456789 17
3333333333333333333333333333 11
Sample Output
0 1 2 3 4 5 6 7 8 9
3 5 5 4 3 2 8 3 5 4 2 8 4
68 77
57 58 59 53 49 57 60 55 51 45 59 55 53 49 56 42 57
14 0 0 14 0 0 0 0 0 0 0

Author:  ZHOU, Yuchen
Source:  ZOJ Monthly, July 2023




/* ***********************************************
Author        :CKboss
Created Time  :2015年08月25日 星期二 10时22分16秒
File Name     :ZOJ3891_2.cpp
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>

using namespace std;

const int maxn=100500;

struct SAM_Node
{
	SAM_Node *fa,*next[10];
	int len,id,pos;
	SAM_Node(){}
	SAM_Node(int _len)
	{
		fa=0; len=_len;
		memset(next,0,sizeof(next));
	}
};

SAM_Node SAM_node[maxn],*SAM_root,*SAM_last;
int SAM_size;

SAM_Node *newSAM_Node(int len)
{
	SAM_node[SAM_size]=SAM_Node(len);
	SAM_node[SAM_size].id=SAM_size;
	return &SAM_node[SAM_size++];
}

SAM_Node *newSAM_Node(SAM_Node *p)
{
	SAM_node[SAM_size]=*p;
	SAM_node[SAM_size].id=SAM_size;
	return &SAM_node[SAM_size++];
}

void SAM_init()
{
	SAM_size=1;
	SAM_root=SAM_last=newSAM_Node(0);
	SAM_node[0].pos=0;
}

void SAM_add(int x,int len)
{
	SAM_Node *p=SAM_last,*np=newSAM_Node(p->len+1);
	np->pos=len; SAM_last=np;
	for(;p&&!p->next[x];p=p->fa)
		p->next[x]=np;
	if(!p)
	{
		np->fa=SAM_root;
		return ;
	}
	SAM_Node *q=p->next[x];
	if(q->len==p->len+1)
	{
		np->fa=q;
		return ;
	}
	SAM_Node *nq=newSAM_Node(q);
	nq->len=p->len+1;
	q->fa=nq; np->fa=nq;
	for(;p&&p->next[x]==q;p=p->fa)
		p->next[x]=nq;
}

void SAM_build(char *s)
{
	SAM_init();
	int len=strlen(s);
	for(int i=0;i<len;i++)
		SAM_add(s[i]-'0',i+1);
}


int du[maxn];
int	ans[40];
int dp[maxn][40];

void solve(int K)
{
	memset(du,0,sizeof(du));
	for(int i=1;i<SAM_size;i++)
	{
		for(int j=0;j<10;j++)
		{
			SAM_Node* to=SAM_node[i].next[j];
			if(to!=0) du[to->id]++;
		}
	}
	queue<int> q;
	for(int i=1;i<SAM_size;i++) if(du[i]==0) q.push(i);

	memset(dp,0,sizeof(dp));

	dp[1][0]=1;

	while(!q.empty())
	{
		int u=q.front(); q.pop();

		for(int i=0;i<10;i++)
		{
			SAM_Node* to=SAM_node[u].next[i];

			if(to==0) continue;
			else
			{
				int v=SAM_node[u].next[i]->id;
				du[v]--;
				if(du[v]==0) q.push(v);
				if(u==1&&i==0) continue;
				for(int j=0;j<K;j++)
				{
					dp[v][(j*10+i)%K]+=dp[u][j];
				}
			}
		}
	}
}

char str[maxn];
int k;

int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);


	while(cin>>str>>k)
	{
		SAM_build(str);
		solve(k);

		memset(ans,0,sizeof(ans));

		for(int i=2;i<SAM_size;i++)
			for(int j=0;j<k;j++) ans[j]=ans[j]+dp[i][j];

		for(int i=0,len=strlen(str);i<len;i++) 
		{
			if(str[i]=='0') { ans[0]++; break; }
		}

		for(int i=0;i<k;i++)
			printf("%d%c",ans[i],(i==k-1)?10:32);
	}

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值