题目大意:求 A 的前缀和 B 的后缀拼接起来能组成多少个字符串。
首先,绝大部分的答案字符串都是不重复的,我们只需要求出来有多少重复的就可以了。
只有 A 和 B 中出现相同的字符,才会出现相同的答案字符串。
样例:
A : tree
B : heap
有两种重复的字符串,而一共有 4*4=16个字符串,于是答案是 16-2=14。
若有一对相同的字符, 就会有一对相同的字符串。而字符只有 26 个,可以参考桶的思想,线性扫一遍两个数组中每个字符的数量,对于每个字符计算会有多少的重复字符串,时间复杂度为 O(N+M)
特殊地,题目要求答案字符串中须同时包含 A 的前缀和 B 的后缀,不能仅包含一个,所以 A 的第一个字符和 B 的最后一个字符是都在每个答案字符串中的,所以无需查询这两个元素。
#include<bits/stdc++.h> using namespace std; typedef long long ll; string a,b; ll n,m,cnta[27],cntb[27],cnt; int main(){ cin>>a>>b; n=a.size(); m=b.size(); a=" "+a; b=" "+b; for(int i=2;i<=n;i++) cnta[a[i]-'a'+1]++; for(int i=1;i<=m-1;i++) cntb[b[i]-'a'+1]++; for(int i=1;i<=26;i++) cnt+=cnta[i]*cntb[i]; cout<<n*m-cnt<<endl; return 0; }
#include <cstring> #include <iostream> using namespace std; char s[510]; int a[1105], b[1105], ans[3005]; int main () { a[1100] = 1; scanf ("%s", s + 1); int len = strlen (s + 1); for (int i = 1; i <= len; i ++) { for (int j = 1100; j >= 1; j --) a[j] *= 125; for (int j = 1100; j >= 1; j --) { a[j - 1] += a[j] / 10; a[j] %= 10; } if (s[i] != '0') { int t = s[i] - 48, fir; for (int j = 1100; j >= 1; j --) b[j] = a[j] * t; for (int j = 1100; j >= 1; j --) { b[j - 1] += b[j] / 10; b[j] %= 10; if (b[j] != 0) fir = j; } int size = 1101 - fir; int na = 3 * i + 1 - size, nb = fir; while (nb != 1101) { ans[na] += b[nb]; na ++; nb ++; } for (int i = 3000; i >= 1; i --) { ans[i - 1] += ans[i] / 10; ans[i] %= 10; } } } int tmp = 0; for (int i = 3000; i >= 1; i --) if (ans[i] != 0 && !tmp) tmp = i; for (int i = 1; i <= tmp; i ++) cout << ans[i]; return 0; }
#include <bits/stdc++.h> using namespace std; const int N = 200010; struct node { int to, nxt, wt; } eg[N * 2]; int n; int far, mx; int dp[N]; int ans[N]; int hd[N], tot; void add(int u, int v, int w) { eg[tot].to = v; eg[tot].wt = w; eg[tot].nxt = hd[u]; hd[u] = tot++; } void dfs(int u, int pre) { for (int i = hd[u]; i != -1; i = eg[i].nxt) { int v = eg[i].to, w = eg[i].wt; if (v != pre) { dp[v] = dp[u] + w; ans[v] = max(ans[v], dp[v]); if (dp[v] > mx) mx = dp[v], far = v; dfs(v, u); } } } int main() { cin >> n; tot = 0, mx = -1; for (int i = 0; i <= n; ++i) hd[i] = -1, ans[i] = 0; for (int i = 2, v; i <= n; ++i) { scanf("%d", &v); add(i, v, 1), add(v, i, 1); } dp[1] = 0; dfs(1, 0); dp[far] = 0; dfs(far, 0); dp[far] = 0; dfs(far, 0); for (int i = 1; i <= n; ++i) { if (i == far) printf("%d", mx); else printf("%d", ans[i]); putchar(' '); } return 0; }
这个题目其实就是区间最值问题,你可以用线段树,分块,st等等来做!
这里面有一个关键词,就是数据是不降的,所以,我们会发现相同的数字肯定会在一起,所以可以考虑进行数字记录!
#include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=1e5+10,len=512; int n,q,a[M],lsh[M]; int L[len],R[len],bel[M]; int pre[len][M];//前 i 块中数字 j 共出现 pre[i][j] 次 int ans[len][len];//第 i~j 块中的众数共出现 ans[i][j] 次 void build(){ int size=sqrt(n); for(int i=1;i<=n;i++) bel[i]=(i-1)/size+1; for(int i=1;i<=bel[n];i++) L[i]=(i-1)*size+1,R[i]=i*size; R[bel[n]]=n; for(int i=1;i<=bel[n];i++){ for(int j=1;j<=lsh[0];j++) pre[i][j]=pre[i-1][j]; for(int j=L[i];j<=R[i];j++) pre[i][a[j]]++; } for(int i=1;i<=bel[n];i++) for(int j=i;j<=bel[n];j++){ ans[i][j]=ans[i][j-1]; for(int k=L[j];k<=R[j];k++) ans[i][j]=max(ans[i][j],pre[j][a[k]]-pre[i-1][a[k]]); } } int buc[M]; int query(int l,int r){ int p=bel[l],q=bel[r],ret=0; if(q-p<=1){ for(int i=l;i<=r;i++) buc[a[i]]++; for(int i=l;i<=r;i++) ret=max(ret,buc[a[i]]); for(int i=l;i<=r;i++) buc[a[i]]=0; }else{ ret=ans[p+1][q-1]; for(int i=l;i<=R[p];i++) buc[a[i]]++; for(int i=L[q];i<=r;i++) buc[a[i]]++; for(int i=l;i<=R[p];i++) ret=max(ret,pre[q-1][a[i]]-pre[p][a[i]]+buc[a[i]]); for(int i=L[q];i<=r;i++) ret=max(ret,pre[q-1][a[i]]-pre[p][a[i]]+buc[a[i]]); for(int i=l;i<=R[p];i++) buc[a[i]]=0; for(int i=L[q];i<=r;i++) buc[a[i]]=0; } return ret; } int main(){ scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) lsh[++lsh[0]]=a[i]; sort(lsh+1,lsh+1+lsh[0]); lsh[0]=unique(lsh+1,lsh+1+lsh[0])-lsh-1; for(int i=1;i<=n;i++) a[i]=lower_bound(lsh+1,lsh+1+lsh[0],a[i])-lsh; build(); for(int i=1,l,r;i<=q;i++){ scanf("%d%d",&l,&r); printf("%d\n",query(l,r)); } return 0; }