首页 > 其他分享 >Living-Dream 系列笔记 第61期

Living-Dream 系列笔记 第61期

时间:2024-07-09 18:09:04浏览次数:17  
标签:insert code string Living int 61 trie Dream cur

退役选手复活后的第一篇。

https://www.luogu.com.cn/problem/SP4033

其实只要一个 insert.

就是插入时没新建节点 \(\to\) 自己是别人前缀,
插入时途经了别人的结束节点 \(\to\) 别人是自己前缀。

code
#include<bits/stdc++.h>
using namespace std;

const int N=3e5+5,M=31;
int n,cnt,in[M];
int tot,trie[N][M];
vector<int> G[M];
string s[N],ans[N];
bool vis[N];

void insert(string s){
	int cur=0;
	for(int i=0;i<s.size();i++){
		if(!trie[cur][s[i]-'a'])
			trie[cur][s[i]-'a']=++tot;
		cur=trie[cur][s[i]-'a'];
	}
	vis[cur]=1; return;
}
bool build(string s){
	int cur=0;
	for(int i=0;i<s.size();i++){
		if(vis[cur]) return 0;
		for(int j=0;j<26;j++) 
			if((int)(s[i]-'a')!=j&&trie[cur][j])
				G[s[i]-'a'].push_back(j),in[j]++;  
		cur=trie[cur][s[i]-'a'];
	}
	return 1;
}
bool topo(){
	queue<int> q; int res=0;
	for(int i=0;i<26;i++)
		if(!in[i]) q.push(i);
	while(!q.empty()){
		int cur=q.front(); 
		q.pop(),res++;
		for(int i:G[cur]){
			in[i]--;
			if(!in[i]) q.push(i);
		}
	}
	return res==26;
}

int main(){
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>s[i],insert(s[i]);
	for(int i=1;i<=n;i++){
		for(int i=0;i<M;i++) G[i].clear();
		memset(in,0,sizeof(in));
		if(build(s[i])&&topo()) ans[++cnt]=s[i];
	}
	cout<<cnt<<'\n';
	for(int i=1;i<=cnt;i++) cout<<ans[i]<<'\n';
	return 0;
}

https://www.luogu.com.cn/problem/P3065

bf 是全排列字典然后依照他去 sort.

考虑转换问题思考角度,尝试将每个字符串作为第一个。

探索性质:

  1. 若一个字符串是别人的前缀,则他永远也成不了第一个

  2. 若一个字符串是第一个,则他向 trie 中与它同层的节点连边,一定不会出现矛盾(即出现环)

第一条很好理解,而第二条实际是说连边后形成的图为 DAG(有拓扑序),这个拓扑序就是满足当前字符串为第一个的字典顺序。

于是我们连边跑 toposort / tarjan 判环即可。

code
#include<bits/stdc++.h>
using namespace std;

const int N=3e5+5,M=31;
int n,cnt,in[M];
int tot,trie[N][M];
vector<int> G[M];
string s[N],ans[N];
bool vis[N];

void insert(string s){
	int cur=0;
	for(int i=0;i<s.size();i++){
		if(!trie[cur][s[i]-'a'])
			trie[cur][s[i]-'a']=++tot;
		cur=trie[cur][s[i]-'a'];
	}
	vis[cur]=1; return;
}
bool build(string s){
	int cur=0;
	for(int i=0;i<s.size();i++){
		if(vis[cur]) return 0;
		for(int j=0;j<26;j++) 
			if((int)(s[i]-'a')!=j&&trie[cur][j])
				G[s[i]-'a'].push_back(j),in[j]++;  
		cur=trie[cur][s[i]-'a'];
	}
	return 1;
}
bool topo(){
	queue<int> q; int res=0;
	for(int i=0;i<26;i++)
		if(!in[i]) q.push(i);
	while(!q.empty()){
		int cur=q.front(); 
		q.pop(),res++;
		for(int i:G[cur]){
			in[i]--;
			if(!in[i]) q.push(i);
		}
	}
	return res==26;
}

int main(){
	cin>>n;
	for(int i=1;i<=n;i++)
		cin>>s[i],insert(s[i]);
	for(int i=1;i<=n;i++){
		for(int i=0;i<M;i++) G[i].clear();
		memset(in,0,sizeof(in));
		if(build(s[i])&&topo()) ans[++cnt]=s[i];
	}
	cout<<cnt<<'\n';
	for(int i=1;i<=cnt;i++) cout<<ans[i]<<'\n';
	return 0;
}

https://www.luogu.com.cn/problem/P4407

考虑一种很 bf 的方法:在 trie 上 dfs。但是她能过。

添加 \(\to\) 原串跳一个字符,询问串不动。

删除 \(\to\) 原串不动,询问串跳一个字符。

替换 \(\to\) 原串、询问串各自跳一个字符。

具体细节见代码。

code
#include<bits/stdc++.h>
using namespace std;

const int N=2e5+5,M=31;
int n,m;
int tot,trie[N][M];
int tagtot,tagx[N];
bool isword,tag[N],vis[N];

void insert(string s){
	int cur=0;
	for(int i=0;i<s.size();i++){
		if(!trie[cur][s[i]-'a'])
			trie[cur][s[i]-'a']=++tot;
		cur=trie[cur][s[i]-'a'];
	}
	vis[cur]=1; return;
}
void search(string s,int cur,int len,bool flag){
	if(len==s.size()&&vis[cur]&&flag){ isword=1; return; }
	if(len==s.size()&&vis[cur]&&!flag){
		if(!tag[cur]) 
			tag[tagx[++tagtot]=cur]=1;
		return;
	}
	if(flag){
		if(len<s.size()) search(s,cur,len+1,!flag);
		for(int i=0;i<26;i++){
			if(trie[cur][i]){
				search(s,trie[cur][i],len,!flag);
				if(i!=(int)(s[len]-'a'))
					search(s,trie[cur][i],len+1,!flag);
			}
		}
	}
	if(trie[cur][s[len]-'a'])
		search(s,trie[cur][s[len]-'a'],len+1,flag);
	if(len>=s.size()) return;
}

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		string w;
		cin>>w,insert(w);
	}
	for(int i=1;i<=m;i++){
		string q; cin>>q;
		for(int j=1;j<=tagtot;j++)
			tag[tagx[j]]=0,tagx[j]=0;
		tagtot=0,isword=0; 
		search(q,0,0,1);
		if(isword) cout<<"-1\n";
		else cout<<tagtot<<'\n';
	}
	return 0;
}

https://www.luogu.com.cn/problem/P4683

又是上题的套路。

考虑一种贪心:把最长的留在最后打印,这样删除字符数更少。显然(?)这是正确的。

于是我们遇到最长的就在 trie 上标记一遍,dfs 时没标记的先跑即可。

在 trie 上 dfs 就保证了前缀不会重复删去又加上。

以后看到要输出方案都可以考虑 dfs。

code
#include<bits/stdc++.h>
using namespace std;

const int N=5e5+5,M=26;
int m,cnt;
string ans,s[25005];
int tot,trie[N][M];
bool vis[N],mk[N];
char ch[N];

void insert(string ss){
	int cur=0;
	for(int i=0;i<ss.size();i++){
		if(!trie[cur][ss[i]-'a'])
			trie[cur][ss[i]-'a']=++tot;
		cur=trie[cur][ss[i]-'a'];
		ch[cur]=ss[i];
	}
	vis[cur]=1;
}
void mark(string ss){
	int cur=0;
	for(int i=0;i<ss.size();i++){
        cur=trie[cur][ss[i]-'a'];
        mk[cur]=1;
	}
}
void search(int cur){
	if(vis[cur]) cnt++,ans+="P";
	if(cnt==m){
		cout<<ans.size()<<'\n';
		for(int i=0;i<ans.size();i++) cout<<ans[i]<<'\n';
    }
	for(int i=0;i<26;i++){
		if(trie[cur][i]&&!mk[trie[cur][i]]){
			ans+=ch[trie[cur][i]];
			search(trie[cur][i]);
			ans+="-";
		}
	}
	for(int i=0;i<26;i++){
		if(trie[cur][i]&&mk[trie[cur][i]]){
			ans+=ch[trie[cur][i]];
			search(trie[cur][i]);
			ans+="-";
		}
	}
}

int main(){
	cin>>m;
	int maxz=0,pos=0;
	for(int i=1;i<=m;i++){
		cin>>s[i];
		if(s[i].size()>maxz)
			maxz=s[i].size(),pos=i;
	}
	for(int i=1;i<=m;i++){
		insert(s[i]);
		if(pos==i) mark(s[i]);
	}
	search(0);
	return 0;
}

标签:insert,code,string,Living,int,61,trie,Dream,cur
From: https://www.cnblogs.com/XOF-0-0/p/18292499

相关文章

  • D661-4577C 液压系统阀门 穆格G45HOAA4VSX2HA
    穆格伺服阀(G45HOAA4VSX2HA)是一种电液比例阀,也被称为伺服阀。宁波秉圣现货供应MOOG-G45HOAA4VSX2HA-D661-4577C电液比例伺服阀。穆格伺服阀的工作原理是通过电磁线圈控制液压流体的流量和方向,从而实现对液压系统的精确控制。我仓库伺服阀现货型号如下:详情咨询可联系秉圣刘工......
  • TPS61040D 升压 输出电压 一加加负载就降低
    TPS61040从5V升压到12V,空载输出电压正常,但是只要有20mA的负载,电压就被拉低到10V以下,研究了很久,一度怀疑时买到假芯片了,立创商城买的,按说不会有问题。后来发现时TPS61040输入端的大电容没有焊接导致,原来这颗IC不光需要输出电容,还需要输入接个大一点的电容。。。加电容后输出......
  • Denso Create Programming Contest 2024(AtCoder Beginner Contest 361)E-F
    E求一条树上的路径,使得走遍整棵树花费最小。我们容易发现树上的某条简单路径只需走一次,除此之外所有的路径都需要走两次,那么显而易见,我们需要求树的直径,之后将剩余的路径权值和乘二加上直径权值就可以。F数学题,对于数学题而言,个人感觉时间复杂度的计算对于题目的求解非常重......
  • AtCoder Beginner Contest 361
    AtCoderBeginnerContest361A-Insert给定一个长度为\(N\)的序列\(A\),现在希望将数字\(X\)插入到序列的第\(K\)个数字后面,变成一个新的序列\(B\)。输出序列\(B\)。\(K,N,A_i,X\le100\)模拟题。先读入\(N,K,X\)。接着在读入\(A\)的过程中一遍读入一遍输出,如果读到了第\(K......
  • abc361
    A-Inserthttps://atcoder.jp/contests/abc361/tasks/abc361_ahttps://atcoder.jp/contests/abc361/submissions/55260626intn,k,x;vector<int>a;intmain(){cin>>n>>k>>x;a.resize(n+1);for(inti=0;i<n+1;......
  • AtCoder Beginner Contest 361)
    推荐个C++编程仓库模板https://github.com/yxc-s/programming-templateA-Insertvoidsolve(){ intn,k,x; cin>>n>>k>>x; vector<int>a(n); for(auto&x:a){ cin>>x; } a.insert(a.begin()+k,x); for(inti=0;......
  • Denso Create Programming Contest 2024(AtCoder Beginner Contest 361)
    DensoCreateProgrammingContest2024(AtCoderBeginnerContest361)\(A\)Insert\(AC\)循环结构。点击查看代码inta[200];intmain(){intn,k,x,i;cin>>n>>k>>x;for(i=1;i<=n;i++){cin>>a[i];cout......
  • ABC361
    A.Insert模拟代码实现n,k,x=map(int,input().split())a=list(map(int,input().split()))a.insert(k,x)print(*a)B.IntersectionofCuboids模拟代码实现#include<bits/stdc++.h>#definerep(i,n)for(inti=0;i<(n);++i)usingnamespacest......
  • AtCoder Beginner Contest 361 补题记录(A~F)
    开题顺序:A-C-F-D-B-E。A直接模拟即可。boolbegmem;#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;classFastIO{public:intread(){into=1,x;charch;while(!isdigit(ch=getchar())){if......
  • 8617 阶乘数字和
    这是一个关于计算阶乘结果所有位上的数字之和的问题。我们可以通过以下步骤来解决这个问题:1.首先,我们需要一个函数来计算阶乘。由于n的范围可以达到50,阶乘的结果可能非常大,所以我们需要使用一个可以处理大整数的数据类型,例如C++中的`std::vector<int>`来存储阶乘的结果。2.......