• 20200930 day24 刷题记录


    1 Trie树(01字典树)

    P2580 于是他错误的点名开始了

    题目背景

    XS中学化学竞赛组教练是一个酷爱炉石的人。 他会一边搓炉石一边点名以至于有一天他连续点到了某个同学两次,然后正好被路过的校长发现了然后就是一顿欧拉欧拉欧拉(详情请见已结束比赛 CON900)。
    题目描述
    这之后校长任命你为特派探员,每天记录他的点名。校长会提供化学竞赛学生的人数和名单,而你需要告诉校长他有没有点错名。(为什么不直接不让他玩炉石。)

    输入输出格式

    输入格式

    第一行一个整数 (n),表示班上人数。
    接下来 (n) 行,每行一个字符串表示其名字(互不相同,且只含小写字母,长度不超过 (50))。
    (n+2) 行一个整数 (m),表示教练报的名字个数。
    接下来 (m) 行,每行一个字符串表示教练报的名字(只含小写字母,且长度不超过 (50))。

    输出格式

    对于每个教练报的名字,输出一行。 如果该名字正确且是第一次出现,输出 OK,如果该名字错误,输出 WRONG,如果该名字正确但不是第一次出现,输出 REPEAT

    输入输出样例

    输入样例 #1
    5  
    a
    b
    c
    ad
    acd
    3
    a
    a
    e
    

    输出样例 #1

    OK
    REPEAT
    WRONG
    

    说明

    • 对于 (40\%) 的数据,(nle 1000)(mle 2000)
    • 对于 (70\%) 的数据,(nle 10^4)(mle 2 imes 10^4)
    • 对于 (100\%) 的数据,(nle 10^4)(m≤10^5)

    题解

    Trie树基本操作。add函数是建树过程。树上操作?

    代码

    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    int t,cnt;
    int n,m;
    int f[600005][105];
    int cd[600005];
    char x[52];
    int vis[600005];
    void add(char c[]){
    	t=0;
    	int len=strlen(c+1);
    	for(int i=1;i<=len;i++){
    		if(!f[t][c[i]-'a']) f[t][c[i]-'a']=++cnt;
    		t=f[t][c[i]-'a'];
    	}
    	cd[t]=1;
    }
    void check(char c[]){
    	t=0;
    	int len=strlen(c+1);
    	for(int i=1;i<=len;i++){
    		t=f[t][c[i]-'a'];
    		if(!t) {printf("WRONG
    ");return;}
    	}
    	if(!cd[t]){printf("WRONG
    ");return;}
    	if(!vis[t]&&cd[t]) {printf("OK
    ");vis[t]=1;return;}
    	else {printf("REPEAT
    ");return ;}
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		memset(x,0,sizeof(x));
    		scanf("%s",x+1);
    		add(x);
    	}
    	scanf("%d",&m);
    	for(int i=1;i<=m;i++){
    		memset(x,0,sizeof(x));
    		scanf("%s",x+1);
    		check(x);
    	}
    	return 0; 
    }
    

    2 P4551 最长异或路径

    题目描述

    给定一棵(n)个点的带权树,结点下标从(1)开始到(N)。寻找树中找两个结点,求最长的异或路径。 异或路径指的是指两个结点之间唯一路径上的所有边权的异或。

    输入输出格式

    输入格式

    第一行一个整数(N),表示点数。
    接下来 (n-1) 行,给出 (u,v,w) ,分别表示树上的 (u) 点和 (v) 点有连边,边的权值是 (w)

    输出格式

    一行,一个整数表示答案。

    输入输出样例

    输入样例 #1
    4
    1 2 3
    2 3 4
    2 4 6
    
    输出样例 #1
    7
    

    说明

    最长异或序列是1-2-3,答案是 7 (=3 ⊕ 4)

    数据范围

    (1le n le 100000;0 < u,v le n;0 le w < 2^{31})

    题解

    orz记得补充

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=2000002;
    int n;
    int head[maxn];
    struct node{
    	int v,w,next;
    }edge[maxn];
    int cnt;
    void add(int u,int v,int w){
    	cnt++;
    	edge[cnt].w=w;
    	edge[cnt].v=v;
    	edge[cnt].next=head[u];
    	head[u]=cnt;
    }
    int sum[maxn];
    void dfs(int x,int fa){
    	for(int i=head[x];i;i=edge[i].next){
    		int v=edge[i].v;
    		int w=edge[i].w;
    		if(v!=fa){
    			sum[v]=sum[x]^w;
    			dfs(v,x);
    		}
    	}
    }
    int tot;
    struct trie{
    	int ch[2];
    }t[maxn];
    void add(int val,int x){
    	for(int i=(1<<30);i;i>>=1){
    		//取出二进制下这个数的当前位置
    		bool c=val&i;
    		if(!t[x].ch[c]) t[x].ch[c]=++tot;
    		x=t[x].ch[c];
    	}
    }
    int query(int val,int x){
    	int ans=0;
    	for(int i=(1<<30);i;i>>=1){
    		bool c=val&i;
    		if(t[x].ch[!c]){
    			ans+=i;
    			x=t[x].ch[!c];//如果这一位可以进行异或就沿着这一条路往下走
    		}
    		else x=t[x].ch[c];
    	}
    	return ans;
    }
    int main(){
    	memset(head,-1,sizeof(head));
    	scanf("%d",&n);
    	
    	for(int i=1;i<=n-1;i++){
    		int u,v,w;
    		scanf("%d%d%d",&u,&v,&w);
    		add(u,v,w);add(v,u,w);
    	}
    	dfs(1,-1);//预处理出每一个节点到根的异或和
    	for(int i=1;i<=n;i++) add(sum[i],0);
    	int ans=0;
    	for(int i=1;i<=n;i++) ans=max(ans,query(sum[i],0));//查询,取最大值
    	printf("%d",ans);
    	return 0;
    }
    

    3 归并排序求逆序对P1908

    题解

    代码

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    #define N 1000005
    int r[N],a[N];
    int n;
    long long ans=0;
    void merge_sort(int s,int t){
    	if(s==t) return ;
    	int mid=s+t>>1;
    	merge_sort(s,mid);
    	merge_sort(mid+1,t);
    	int i=s,j=mid+1,k=s;
    	while(i<=mid&&j<=t){
    		if(a[i]<=a[j]) r[k++]=a[i++];
    		else r[k++]=a[j++],ans+=(long long)mid-i+1;
    	}
    	while(i<=mid) r[k]=a[i],k++,i++;
    	while(j<=t) r[k]=a[j],k++,j++;
    	for(int i=s;i<=t;i++){
    		a[i]=r[i];
    	}
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&a[i]);
    	}
    	merge_sort(1,n);
    	printf("%lld",ans);
    	return 0;
    }
    
    要做就做南波万
  • 相关阅读:
    使用Google浏览器做真机页面调试
    JavaScript从作用域到闭包
    用canvas实现一个colorpicker
    你还在为移动端选择器picker插件而捉急吗?
    我是这样写文字轮播的
    高性能JS-DOM
    ExtJs4学习(四):Extjs 中id与itemId的差别
    MongoDB 安装与启动
    UML应用:业务内涵的分析抽象&amp;表达
    MySQL 错误日志(Error Log)
  • 原文地址:https://www.cnblogs.com/liuziwen0224/p/20200930day24-001.html
Copyright © 2020-2023  润新知