2021.09.11 CF1547G How Many Paths & Luogu P5546

Keywords: data structure Binary Search

;

CF1547G   How   Many   Paths \color{green}{\texttt{CF1547G How Many Paths}} CF1547G How Many Paths

[Problem] \color{blue}{\texttt{[Problem]}} [Problem]

[Solution] \color{blue}{\texttt{[Solution]}} [Solution]

First, if a point u u u has a self ring and 1 1 1 can reach u u u. So ans u \text{ans}_{u} ansu , obviously − 1 -1 − 1 (because you can run in the self loop any time).

Second, if from u u u in a point greater than 1 1 On the strongly connected component of 1, then ans u = − 1 \text{ans}_{u}=-1 ansu = − 1 (because you can run any number of times in a strongly connected component).

Again, if from 1 1 1 to x x The path of x passes through a point u u u satisfied ans u = − 1 \text{ans}_{u}=-1 ansu = − 1, then ans x = − 1 \text{ans}_{x}=-1 ansx = − 1 (think about why).

Therefore, we can use tarjan to shrink the point, and then sort the topology.

However, this is only oral AC, and there is still a certain distance from procedural AC.

This is a detailed question. There are many points to pay attention to:

  • When initializing the topology queue, only points can be 1 1 Join the queue at the strongly connected component of 1. Otherwise, there will be a point u u u is unreachable, but it is accessed, resulting in the wrong answer.
  • Because at the beginning, only the point 1 1 1 joined the queue, so the penetration of the point cannot be equal to 0 0 0, otherwise it may not be accessed for a lifetime. You should visit the point u u u is added to the queue.
  • Because we visited the point u u When u u u u joined the queue, so you should limit the number of times to join the queue at each point, otherwise TLE will occur. Program implementation 70 70 70 times to AC.
  • Memset cannot be used when initializing an array, because a single memset is O ( size ) \mathcal{O}(\text{size}) O(size). When the number of input data groups is large, TLE will be. You should empty it with violence.

In fact, I haven't finished here. See the code for details. Pay attention to all the notes.

[code] \color{blue}{\texttt{[code]}} [code]

inline int ckmin(int &a,int b){
	return (a=((a<b)?a:b));
}
inline int ckmax(int &a,int b){
	return (a=((a>b)?a:b));
}

const int N=4e5+100;
const int inf=0x3f3f3f3f;

struct edge{
	int next,to;
}e[N],E[N];int h[N],te,H[N],Te;
inline void add(int u,int v){
	e[++te]=(edge){h[u],v};h[u]=te;
}
inline void Add(int u,int v){
	E[++Te]=(edge){H[u],v};H[u]=Te;
}

int Stack[N],stack_top;
int dfn[N],low[N],dfscnt;
int belong[N],num[N],scc;
void tarjan(int u){
	Stack[++stack_top]=u;
	dfn[u]=low[u]=++dfscnt;
	
	for(int i=h[u];i;i=e[i].next){
		register int v=e[i].to;
		if (!dfn[v]){
			tarjan(v);
			ckmin(low[u],low[v]);
		}
		else if (!belong[v])
			ckmin(low[u],dfn[v]);
	}
	
	if (dfn[u]==low[u]){
		num[belong[u]=++scc]=1;
		
		while (Stack[stack_top]!=u){
			int v=Stack[stack_top--];
			num[belong[v]=scc]++;
		}
		
		--stack_top;
	}
}

int n,m,ans[N],ind[N];
bool UniQue[N];//Is there a self loop 

inline void init_data(int n){
	te=Te=scc=dfscnt=stack_top=0;
	for(int i=1;i<=n;i++) h[i]=H[i]=0;
	for(int i=1;i<=n;i++) ans[i]=num[i]=0;
	for(int i=1;i<=n;i++) dfn[i]=low[i]=0;
	for(int i=1;i<=n;i++) ind[i]=Stack[i]=0;
	for(int i=1;i<=n;i++) belong[i]=0;
	for(int i=1;i<=n;i++) UniQue[i]=true;
}//Cannot use memset 

inline void build_new_graph(){
	for(int u=1;u<=n;u++)
		for(int i=h[u];i;i=e[i].next){
			register int v=e[i].to;
			if (belong[u]!=belong[v]){
				Add(belong[u],belong[v]);
				++ind[belong[v]];
			}
		}
}

inline void topo_sort(){
	for(int i=1;i<=n;i++)
		if (num[belong[i]]==1&&!UniQue[i])
			num[belong[i]]=inf;
	
	if (num[belong[1]]>1)
		ans[belong[1]]=-1;
	else ans[belong[1]]=1;
	
	queue<int> q;
	q.push(belong[1]);
	
	while (!q.empty()){
		int u=q.front();q.pop();
		for(int i=H[u];i;i=E[i].next){
			register int v=E[i].to;//Note case E 
			if (num[v]>1||ans[u]==-1) ans[v]=-1;
			else if (ans[v]!=-1) ans[v]++;//It cannot be written as ans[v]+=ans[u], and pay attention to the conditions 
			if (ans[v]<=70) q.push(v);//Be careful to limit the number of times you join the team 
		}
	}
}

int main(){
	for(int T=1,Q=read();T<=Q;T++){
		n=read();m=read();
		
		init_data(n);
		
		for(int i=1,u,v;i<=m;i++){
			u=read();v=read();
			if (u!=v) add(u,v);
			else UniQue[u]=false;
		}
		
		for(int i=1;i<=n;i++)
			if (!dfn[i]) tarjan(i);//Be careful that the whole graph is not connected 
		
		build_new_graph();
		
		topo_sort();
		
		for(int i=1;i<=n;i++)
			if (ans[belong[i]]>=2) printf("2 ");//You can't omit here 
			else printf("%d ",ans[belong[i]]);
		printf("\n");
	}
	
	return 0;
}

In fact, the code is not very long, but there are a lot of empty lines.

From this question, we can see that there is a difference between oral AC and code AC.

Luogu   P5546   [POI2000] common string \color{green}{\texttt{Luogu P5546 [POI2000] public string}} Luogu   P5546   [POI2000] common string

[Problem] \color{blue}{\texttt{[Problem]}} [Problem]

seek n n The longest common substring of n strings.

[Solution] \color{blue}{\texttt{[Solution]}} [Solution]

First of all, to understand, string a , b a,b a. The longest common substring sum of B c c The longest common substring of c is not a , b , c a,b,c a. The longest common substring of B, C.

It's a bit awkward. Let's take an example: a a a is abbac, b b b is acabb, c c c is ACC, then a , b a,b a. The longest common substring of B is abb, abb and c c The longest common substring of c is a. however a , b , c a,b,c a. The longest common substring of B and C is ac.

We find that the answer is as long as we find the length of the longest common substring, and this thing is monotonic (i.e. dichotomy). So we can split.

Consider how to judge n n Whether one of the n strings has a length not less than x x Common substring of x.

First calculate the hash value of each string.

For section i i i strings, we extract each of which has a length of x x Substring of x, and then use set to record the second string i i i strings contain this substring. Finally, determine whether there is a substring, which is used by all n n n can be contained in the string.

Final time complexity O ( n l log ⁡ n log ⁡ l ) \mathcal{O}(nl \log n \log l) O(nllognlogl). among l l l is the length of the string.

However, the positive solution of this problem is suffix automata. Of course, I'm too delicious. I only know two points + hash.

[code] \color{blue}{\texttt{[code]}} [code]

const int N=20,M=10010;
const int inf=0x3f3f3f3f;

char s[N][M];int len[N];
long long haSh[N][M],Pow[M];

int n,m,l,r,mid,ans;

inline void init_hash(){
	Pow[0]=1;
	for(int i=1;i<=m;i++)
		Pow[i]=Pow[i-1]*233;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=len[i];j++)
			haSh[i][j]=haSh[i][j-1]*233+(s[i][j]-'a');
}

inline long long Hash(int k,int l,int r){
	return haSh[k][r]-haSh[k][l-1]*Pow[r-l+1];
}

inline bool check(int mid){
	map<int,set<int> > pos;
	
	for(int i=1;i<=n;i++)
		for(int j=mid;j<=len[i];j++)
			if (pos[Hash(i,j-mid+1,j)].find(i)==pos[Hash(i,j-mid+1,j)].end())
				pos[Hash(i,j-mid+1,j)].insert(i);
	
	for(int i=mid;i<=len[1];i++)
		if (pos[Hash(1,i-mid+1,i)].size()==n)
			return true;
	
	return false;
}

int main(){
    scanf("%d",&n);m=inf;
	
	for(int i=1;i<=n;i++){
		scanf("%s",s[i]+1);
		len[i]=strlen(s[i]+1);
		m=min(m,len[i]);
	}
	
	init_hash();
	
	l=1;r=m;ans=0;
	while (l<=r){
		mid=(l+r)>>1;
		if (check(mid)){
			ans=mid;
			l=mid+1;
		}
		else r=mid-1;
	}
	
	printf("%d",ans);
	
	return 0;
}

Posted by bradleybebad on Sat, 11 Sep 2021 17:46:05 -0700