num1
大概思路:题目要求的是,第一个完美排列出现的位置,而后看数据范围,给出的数值最大是5,那么咱们能够考虑,把这两个串合成一个,A[i] = a[i] * 6 + b[i];,
对于给出的大串也是如此B[i] = c[i] * 6 + d[i]; 而后就是直接kmp匹配,找到出现的第一个位置,变成kmp模板题
node
#include <bits/stdc++.h> using namespace std; const int mn = 1e6 + 10; int n, m; int nx[mn]; void cal_next(int b[]) { memset(nx, 0, sizeof nx); nx[0] = -1; int k = -1; int j = 0; while (j < m) { if (k == -1 || b[j] == b[k]) { j++; k++; nx[j] = k; } else k = nx[k]; } } int KMP(int a[], int b[]) { cal_next(b); int i = 0, j = 0; while (i < n && j < m) { if (j == -1 || a[i] == b[j]) i++, j++; else j = nx[j]; } if (j >= m) return i - m + 1; else return 0; } int a[mn], b[mn]; int c[mn], d[mn]; int A[mn], B[mn]; int main() { cin >> m; for (int i = 0; i < m; i++) scanf("%d", &a[i]); for (int i = 0; i < m; i++) scanf("%d", &b[i]); for (int i = 0; i < m; i++) A[i] = a[i] * 6 + b[i]; cin >> n; for (int i = 0; i < n; i++) scanf("%d", &c[i]); for (int i = 0; i < n; i++) scanf("%d", &d[i]); for (int i = 0; i < n; i++) B[i] = c[i] * 6 + d[i]; cout << KMP(B, A) << endl; return 0; } /* 2 3 4 3 4 8 0 0 0 0 3 4 0 0 0 0 0 0 3 4 0 0 */
num2
裸的记忆化搜索,因为有单调性,不难想到DP。要计算某点A为起点的最长水沟长度lenA,先计算A的上下左右四个点B1\B2\B3\B4中比A低的点如B一、B2的水沟长度,计B一、B2为起点的最长水沟长度为lenB一、lenB2,则lenA = max(lenB1, lenB2) + 1,若是四周没有比A低的点则lenA = 1;c++
void DFS(int nowx,int nowy) { if(dp[nowx][nowy]) return ; dp[nowx][nowy]=1; for(int i=0;i<=3;i++){ int tx=nowx+x[i]; int ty=nowy+y[i]; if(tx>=1&&tx<=N&&ty>=1&&ty<=M&&a[nowx][nowy]>a[tx][ty]){ DFS(tx,ty); dp[nowx][nowy]=max(dp[nowx][nowy],dp[tx][ty]+1); } } ans=max(ans,dp[nowx][nowy]); } for(int i=1;i<=N;i++) for(int j=1;j<=M;j++) DFS(i,j);
num3:
题意:给定一棵树,问最大亦或路径。
思路: 首先最大亦或,得须要用01Trie来作,若是你不会,那么这题应该就不会了。(劝退)
1,先介绍一下什么是Trie字典树:给你一本字典,让你查里面是否有某个单词,好比‘bcd’,你应该会看是否有b开头的单词,而后看‘bc’,而后看‘bcd’。 这个的话,想象一个树,从根往下,连起来就是这个单词。 咱们把单词都插入这个树里,就造成了一颗字典树,若是查单词,那么就从根向下查便可。 这个相比hash的好处:(1)不会出现hash那样的差错。(2)前缀重复的地方能够节省空间。
spa
2,其次是要知道亦或的性质: a到b的亦或=a到根的亦或XORb到根的亦或。 因此咱们求出每一个点到根的亦或值,假设如今的亦或为a[]。 如今就是要在这些a[]里面找两个数,使得他们的亦或最大。code
3,知道的性质2,和字典树。 咱们就能够着手处理此题了。不过咱们如今不是找单词,而是找最大亦或,咱们把a[]集合的数都变为2进制,按高位到地位一次插入树里,如今要在集合里面找最大亦或,等效于高位尽量不同。 因此得尽可能走反向,即我若是是1,我就看儿子节点是否有0…这在query里面获得体现。ci
#include<bits/stdc++.h> using namespace std; const int maxn=200010; int Laxt[maxn],Next[maxn],To[maxn],cnt; int W[maxn],ch[maxn*30][2],ans,node; void add(int u,int v) { Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; } void dfs(int u,int f) { W[u]=W[f]^W[u]; for(int i=Laxt[u];i;i=Next[i]){ int v=To[i]; if(To[i]==f) continue; dfs(To[i],u); } } int query(int x) { int now=0,res=0; for(int i=30;i>=0;i--){ int t=(x>>i)&1; if(ch[now][1-t]) res+=(1<<i),now=ch[now][1-t]; else now=ch[now][t]; } return res; } int insert(int x) { int now=0; for(int i=30;i>=0;i--){ int t=(x>>i)&1; if(!ch[now][t]) ch[now][t]=++node; now=ch[now][t]; } } int main() { int N,id,x; scanf("%d",&N); for(int i=1;i<=N;i++){ scanf("%d",&id); scanf("%d",&W[id]); for(int j=1;j<=2;j++){ scanf("%d",&x); if(x!=-1){ add(id,x); add(x,id); } } } dfs(1,0); for(int i=1;i<=N;i++){ if(i>1) ans=max(ans,query(W[i])); insert(W[i]); } printf("%d\n",ans); return 0; } /* 5 1 1 2 3 2 4 -1 -1 3 2 -1 4 4 5 -1 5 5 3 -1 -1 */