洛谷-算法2-4-字符串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,3 时,答案是 7=3⊕4,取最大值。

数据范围

1≤n≤105;0<u,v≤n;0≤w<231。

实现代码:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
struct qwq{
    int v;
    int w;
    int nxt;
}edge[2000001];
int head[2000001];
int cnt=-1;
void add(int u,int v,int w){
    edge[++cnt].nxt=head[u];
    edge[cnt].v=v;
    edge[cnt].w=w;
    head[u]=cnt;
}
int sum[2000001];
void dfs(int x,int fa){
    for(int i=head[x];~i;i=edge[i].nxt){
        int v=edge[i].v;
        int w=edge[i].w;
        if(v!=fa){
            sum[v]=sum[x]^w;
            dfs(v,x);
        }
    }
}
struct trie{
    int ch[2];
}t[2000001];
int tot;
void build(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));
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;++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)build(sum[i],0);
    int ans=0;
    for(int i=1;i<=n;++i){
        ans=max(ans,query(sum[i],0));
    }
    printf("%d\n",ans);
} 

P5283 [十二省联考 2019] 异或粽子

题目描述

小粽是一个喜欢吃粽子的好孩子。今天她在家里自己做起了粽子。

小粽面前有 n 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 1 到 n。第 i 种馅儿具有一个非负整数的属性值 ai​。每种馅儿的数量都足够多,即小粽不会因为缺少原料而做不出想要的粽子。小粽准备用这些馅儿来做出 k 个粽子。

小粽的做法是:选两个整数数 l, r,满足 1⩽l⩽r⩽n,将编号在 [l,r] 范围内的所有馅儿混合做成一个粽子,所得的粽子的美味度为这些粽子馅儿的属性值的异或和 。(异或就是我们常说的 xor 运算,即 C/C++ 中的 ˆ 运算符或 Pascal 中的 xor 运算符)

小粽想品尝不同口味的粽子,因此她不希望用同样的馅儿的集合做出一个以上的粽子。

小粽希望她做出的所有粽子的美味度之和最大。请你帮她求出这个值吧!

输入格式

第一行两个正整数 n, k,表示馅儿的数量,以及小粽打算做出的粽子的数量。

接下来一行为 n 个非负整数,第 i 个数为 ai​,表示第 i 个粽子的属性值。 对于所有的输入数据都满足:1⩽n⩽5×105, 1⩽k⩽min{2n(n−1)​,2×105}, 0⩽ai​⩽4294967295。

输出格式

输出一行一个整数,表示小粽可以做出的粽子的美味度之和的最大值。

输入输出样例

输入 #1复制

复制代码
3 2
1 2 3

输出 #1复制

复制代码
6

说明/提示

测试点 n k
1, 2, 3, 4, 5, 6, 7, 8 ⩽103 ⩽103
9, 10, 11, 12 ⩽5×105 ⩽103
13, 14, 15, 16 ⩽103 ⩽2×105
17, 18, 19, 20 ⩽5×105 ⩽2×105

实现代码:

cpp 复制代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=20000000+10;
struct Node{int id,rk;long long w;bool operator <(const Node &a)const{return w<a.w;}};
priority_queue<Node>q;
long long ans=1,x,s[N];
int a[N][2],size[N],n,m,tot;
void ins(long long x)
{
    int u=0;
    for(int i=31;i>=0;i--)
    {
        int ch=(x>>i)&1;size[u]++;
        if(!a[u][ch])a[u][ch]=++tot;
        u=a[u][ch];
    }
    size[u]++;
}
long long query(long long x,int rk)
{
    int u=0;long long ans=0;
    for(int i=31;i>=0;i--)
    {
        int ch=(x>>i)&1;
        if(!a[u][ch^1])u=a[u][ch];
        else if(rk<=size[a[u][ch^1]])u=a[u][ch^1],ans|=1LL<<i;
        else rk-=size[a[u][ch^1]],u=a[u][ch];
    }
    return ans;
}
long long getin()
{
    long long x=0;char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();
    return x;
}
int main()
{
    n=getin(),m=getin();m<<=1;
    for(int i=1;i<=n;i++)x=getin(),s[i]=s[i-1]^x;
    for(int i=0;i<=n;i++)ins(s[i]);
    for(int i=0;i<=n;i++)q.push((Node){i,1,query(s[i],1)});
    for(int i=1;i<=m;i++)
    {
        Node t=q.top();ans+=t.w;q.pop();
        if(t.rk<n)q.push((Node){t.id,t.rk+1,query(s[t.id],t.rk+1)});
    }
    cout<<(ans>>1)<<endl;
}

P1470 [IOI 1996 / USACO2.3] 最长前缀 Longest Prefix

题目描述

在生物学中,一些生物的结构是用包含其要素的大写字母序列来表示的。生物学家对于把长的序列分解成较短的序列(即元素)很感兴趣。

如果一个集合 P 中的元素可以串起来(元素可以重复使用)组成一个序列 S,那么我们认为序列 S 可以分解为 P 中的元素。元素不一定要全部出现(如下例中 BBC 就没有出现)。举个例子,序列 ABABACABAAB 可以分解为下面集合中的元素:{A,AB,BA,CA,BBC}

序列 S 的前面 k 个字符称作 S 中长度为 k 的前缀。设计一个程序,输入一个元素集合以及一个大写字母序列,设 S′ 是序列 S 的前缀,使其可以分解为给出的集合 P 中的元素,求 S′ 的长度 k 的最大值。

输入格式

输入数据的开头包括若干个元素组成的集合 P,用连续的以空格分开的字符串表示。字母全部是大写,数据可能不止一行。元素集合结束的标志是一个只包含一个 . 的行,集合中的元素没有重复。

接着是大写字母序列 S,用字符串表示,每 76 个字符换一行。

输出格式

只有一行,输出一个整数,表示 S 符合条件的前缀的最大长度。

输入输出样例

输入 #1复制

复制代码
A AB BA CA BBC
.
ABABACABAABC

输出 #1复制

复制代码
11

说明/提示

【数据范围】

对于 100% 的数据,1≤card(P)≤200,1≤∣S∣≤2×105,P 中的元素长度均不超过 10。

翻译来自 NOCOW。

实现代码:

cpp 复制代码
#include <iostream>
#include <set>
#include <cstring>
using namespace std;
int dp[200005],m;
set<string> s[20];
int main(){
	string tp;
	while (cin>>tp){
		if (tp==".") break;
		s[tp.size()].insert(tp);
		m=max(m,int(tp.size()));
	}
	int i,ans=0;
	dp[0]=1;
	string n;
	n=" ";
	while (cin>>tp){
		n=n+tp;
	}
	for (i=1;i<n.size();i++){
		for (int j=min(i,m);j>=1;j--){
			string tt=n.substr(i-j+1,j);
			if (s[tt.size()].count(tt)==1&&dp[i-j]==1){
				ans=i;
				dp[i]=1;
				break;
			}
		}
	}
	cout<<ans;
}

CF25E Test

题目描述

给定 3 个字符串 s1​,s2​,s3​,试求一个字符串,使 s1​,s2​,s3​ 都是这个字符串的子串,并使这个字符串最短。输出最短字符串的长度 l。

输入格式

第一行输入一个字符串,表示 s1​。

第二行输入一个字符串,表示 s2​。

第三行输入一个字符串,表示 s3​。

输出格式

第一行输出一个正整数,表示答案 l。

显示翻译

题意翻译

输入输出样例

输入 #1复制

复制代码
ab
bc
cd

输出 #1复制

复制代码
4

输入 #2复制

复制代码
abacaba
abaaba
x

输出 #2复制

复制代码
11

说明/提示

1≤∣s1​∣,∣s2​∣,∣s3​∣≤105。

实现代码:

cpp 复制代码
#include <cstdio>
#include <cstring>
#define min(a,b) ((a)<(b))?(a):(b)
using namespace std;
const int INF=2147483646;
int nxt[4][100050],l[4];
char s[4][100050];
inline void Pre(){
    for(int f=1;f<4;++f){
        int p=0,len=l[f];
        for(int i=2;i<=len;++i){
            while(p&&s[f][i]!=s[f][p+1]) p=nxt[f][p];
            if(s[f][i]==s[f][p+1]) ++p;
            nxt[f][i]=p;
        }
    }
    return ;
}
int f(int a,int b,int c){ 
    int ans=INF,p1=0;
    int al=l[a],bl=l[b],cl=l[c];
    for(int i=1;i<=al;++i){
        while(p1&&s[b][p1+1]!=s[a][i]) p1=nxt[b][p1];
        if(s[b][p1+1]==s[a][i]) ++p1;
        if(p1==bl){
            p1=-1;
            break;
        }
    }
    if(p1==-1){
        int p=0;
        for(int i=1;i<=al;++i){
            while(p&&s[c][p+1]!=s[a][i]) p=nxt[c][p];
            if(s[c][p+1]==s[a][i]) ++p;
            if(p==cl){
                p=-1;
                break;
            }
        }
        if(p==-1) ans=al;
        else ans=al+cl-p;
    }
    else{
        int p=0;
        for(int i=1;i<=al;++i){
            while(p&&s[c][p+1]!=s[a][i]) p=nxt[c][p];
            if(s[c][p+1]==s[a][i]) ++p;
            if(p==cl){
                p=-1;
                break;
            }
        }
        if(p!=-1){
            int p2=p;
            for(int i=p1+1;i<=bl;++i){
                while(p2&&s[c][p2+1]!=s[b][i]) p2=nxt[c][p2];
                if(s[c][p2+1]==s[b][i]) ++p2;
                if(p2==cl){
                    p2=-1;
                    break;
                }
            }
            if(p2==-1) ans=al+bl-p1;
            else ans=al+bl-p1 + cl -p2;
        }
        else ans=al+bl-p1;
    }
    return ans;
}
int main(){
    scanf("%s%s%s",s[1]+1,s[2]+1,s[3]+1);
    int ans=INF;
    l[1]=strlen(s[1]+1);l[2]=strlen(s[2]+1);l[3]=strlen(s[3]+1);
    Pre();
    ans=min(ans,f(1,2,3));ans=min(ans,f(1,3,2));
    ans=min(ans,f(2,1,3));ans=min(ans,f(2,3,1));
    ans=min(ans,f(3,2,1));ans=min(ans,f(3,1,2));
    printf("%d",ans);
    return 0;
}
相关推荐
cpp_25017 小时前
P3374 【模板】树状数组 1
数据结构·c++·算法·题解·洛谷·树状数组
郝学胜-神的一滴7 小时前
干货版《算法导论》 02 :算法效率核心解密
java·开发语言·数据结构·c++·python·算法
stolentime7 小时前
AT_agc061_d [AGC061D] Almost Multiplication Table题解
c++·算法·构造
布吉岛的石头7 小时前
Java 岗,面试常问 100 题(精简版)
java·开发语言·面试
WL_Aurora7 小时前
Python 算法基础篇之回溯
python·算法
智者知已应修善业7 小时前
【51单片机控制的交通信号灯三按键切换调节时分秒加减】2023-8-26
c++·经验分享·笔记·算法·51单片机
01漫游者7 小时前
JavaScript内存管理与闭包
开发语言·javascript·ecmascript
MicroTech20257 小时前
量子退火赋能:微算法科技(NASDAQ: MLGO)图像分割算法开启未来科技新视界
科技·算法·量子计算
枕星而眠7 小时前
C语言数组专题:从一维到二维,吃透内存与指针
java·数据结构·算法