总结:数据结构fw惨遭翻车…呜呜呜
T1
题目大意:给出两个长度为k的字符串 a , b a,b a,b,两个长度为n的字符串 c , d c,d c,d ( k < = n ) (k<=n) (k<=n),求一个最小的 l l l,使得在 c , d c,d c,d中l开头的长度为k的子串刚好与 a , b a,b a,b匹配。
n , k < = 1 e 6 n,k<=1e6 n,k<=1e6
来了来了!!又又又又是笔试喜闻乐见必有的hash题!!!
(真就连着n场都有hash呗,大家都懂了吧,学好hash,笔试必过.jpg)
C++代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ull unsigned long long
#define maxn 10000005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
inline int read()
{
int x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') {
x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
return w==1?x:-x;
}
ull h1[maxn],h2[maxn],p1,p2,B[maxn];
int n,k,x;
inline ull gh(int l,int r,int opt)
{
if(opt==1) return h1[r]-h1[l-1]*B[r-l+1];
else return h2[r]-h2[l-1]*B[r-l+1];
}
int main()
{
freopen("t1.in","r",stdin);
k=read(); B[0]=1; rep(i,1,maxn-5) B[i]=B[i-1]*233;
rep(i,1,k) x=read(),p1=p1*233+x;
rep(i,1,k) x=read(),p2=p2*233+x;
n=read();
rep(i,1,n) x=read(),h1[i]=h1[i-1]*233+x;
rep(i,1,n) x=read(),h2[i]=h2[i-1]*233+x;
int F=0;
rep(l,1,n)
{
int r=l+k-1; if(r>n) break;
ull x1=gh(l,r,1),x2=gh(l,r,2);
if(x1==p1&&x2==p2) {
F=l; break;}
}
cout<<F<<endl;
return 0;
}
T2
题目大意:给出n*m的矩阵,单次可以向四方向中小于自己权值的地方走,要求自选一个起点,求一条长度最长的路径。
n , m < = 1000 n,m<=1000 n,m<=1000
直接放原题链接吧: S H O I 2002 SHOI2002 SHOI2002 滑雪
记忆化搜索,考虑 d p [ i ] [ j ] dp[i][j] dp[i][j]为在 ( i , j ) (i,j) (i,j)位置的最长路。
那么由于每个点只会被dfs一遍,所以整体复杂度就是 O ( n ∗ m ) O(n*m) O(n∗m)了…
可能不太好理解,但是详见代码吧…代码挺是很好理解的。
Java代码:
import java.io.*;
import java.util.*;
public class zbr01
{
public static int [][]a=new int [1005][1005];
public static int [][]dp=new int [1005][1005];
public static int [][]k={
{
1,0},{
0,1},{
-1,0},{
0,-1}};
public static int n,m,ans;
public static int dfs(int x,int y)
{
if(dp[x][y]!=0) return dp[x][y];
for(int i=0;i<=3;i++)
{
int tx=x+k[i][0],ty=y+k[i][1];
if(tx<1||ty<1||tx>n||ty>m||a[tx][ty]>=a[x][y]) continue;
dp[x][y]=Math.max(dp[x][y],1+dfs(tx,ty));
}
return dp[x][y];
}
public static void main(String[] args)
{
Scanner S=new Scanner(System.in);
n=S.nextInt(); m=S.nextInt();
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=S.nextInt();
for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) ans=Math.max(ans,dfs(i,j));
System.out.println(ans+1);
}
}
T3
题目大意:给出一颗固定形态,根节点的点权二叉树,求一条“只能向下走的”xor路径的最大值(xor路径权值为:路径上所有节点的异或值)。
n < = 1 e 5 n<=1e5 n<=1e5
看错题无数次…
(前置知识)
首先考虑这样一个问题“在长度为n的数列中,选择两个数进行xor的最大值”。
这个问题可以使用01trie解决…大家可以去百度学习一下…
那么这个问题中,我们考虑首先预处理出, w [ x ] w[x] w[x]为x到根节点的路径xor值,那么一条只能向下走的路径xor值,便转换为了 w[x]^(w[所有父节点])的max。
这个部分可以用以下伪代码表示:
void dfs(int u)
{
trie插入当前值;
trie查询当前的xor最大值
dfs(儿子节点);
trie删除当前值;
}
即可完成题目要求。
(由于弱菜博主突然智障…忘了怎么写trie删除…写了个可持久化01trie…最后也没能调试出来…呜呜呜
upd:
吐槽:怎么好像大家 O ( n 2 ) O(n^2) O(n2)的都被放过了啊…强烈谴责…啥数据啊,出题人写题都不考虑卡掉大暴力吗…强烈谴责!!!直接造一条链都能卡掉吧…这数据太不合格了hhh