1. 程式人生 > 其它 >2022春每日一題:Day 32

2022春每日一題:Day 32

題目:[USACO12DEC]First! G

不太記得當時怎麼想的了,但是顯然,當一個字串的字首存在則他一定不是first,然後做法:對於每個字串,把每個字元結尾跟他有相同字首的單詞的同元素建邊,保證這個元素嚴格大於其他元素,然後判環,有環的話說明不能是first,反之則是。

程式碼:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <string>
#include <queue>
#include <iostream>
const int N=3e4+5,M=3e5+5;
using namespace std;
int n,m,tot,num,ss[N],vis[N],rd[26];
string s,dic[N];
vector <int> g[26];
namespace trietree
{
	struct trie
	{
		int son[26],tag;
	}e[M];
	void insert(int len)
	{
		int p=0;
		for(int i=0;i<len;i++)
		{
			int k=s[i]-'a';
			if(!e[p].son[k])
			    e[p].son[k]=++tot;
			p=e[p].son[k];
		}
		e[p].tag=1;
	}
	bool topusort()
	{
		queue <int> q;
		while(!q.empty())
		    q.pop();
		int cnt=0;
		for(int i=0;i<26;i++)
		    if(!rd[i])
		        q.push(i);
		while(!q.empty())
		{
			int now=q.front();
			int len=g[now].size();
			++cnt;
			q.pop();
			for(int i=0;i<len;i++)
			{
				int k=g[now][i];
				--rd[k];
				if(!rd[k])
				    q.push(k);
			}
		}
		return cnt==26;
	}
	void clear(int len,int id)
	{
		int p=0,ok=0;
		s=dic[id];
		for(int i=0;i<26;i++)
		    g[i].clear(),rd[i]=0;
		for(int i=0;i<len;i++)
		{
			if(e[p].tag)
			    ok=1;
			int k=s[i]-'a';
			for(int j=0;j<26;j++)
			    if(j!=k && e[p].son[j])
			        g[k].push_back(j),rd[j]++;
			p=e[p].son[k];
		}
		if(!topusort())
		    ok=1;
		if(ok)
		    vis[id]=1;
		num+=ok;
	}
}
using namespace trietree;
int main()
{
	ios::sync_with_stdio(0);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>s;
		ss[i]=s.length();
		dic[i]=s;
		insert(ss[i]);
	}
	for(int i=1;i<=n;i++)
	    clear(ss[i],i);
	cout<<n-num<<'\n';
	for(int i=1;i<=n;i++)
	    if(!vis[i])
	        cout<<dic[i]<<'\n';
	return 0;
}