字符串基础
字符串基础
拖了挺久的了,趁集训推完了。
Hash
个人感觉变化挺多的。
类似进制数。
多和二分结合。
核心代码
class HASH{
public:
int HS[N];
inline void mk(char* s){For(i,0,strlen(s)-1,1) HS[i+1]=(1ll*HS[i]*P%MOD+s[i])%MOD;}
inline int get(int l,int r){return (HS[r]-1ll*HS[l-1]*pw[r-l+1]%MOD+MOD)%MOD;}
}ha[N],hb[N];
-
Bovine Genomics
双指针。
有点滑动窗口的感觉。
\(l,r\) 枚举区间,合法 \(l++\),非法 \(r++\),合法时取个 \(min\) 即为答案。
CODE
#include<bits/stdc++.h> using namespace std; typedef long long llt; typedef unsigned long long ull; const int N=503,MOD=10000132,P=131; #define For(i,a,b,c) for(register int $L=a,$R=b,$C=c,$D=(0<=$C)-($C<0),i=$L;i*$D<=$R*$D;i+=$C) int n,m,pw[N]; char ls[N]; int pd[MOD]; namespace IO{ template<typename T> inline void write(T x){ static T st[45];T top=0;if(x<0)x=~x+1,putchar('-'); do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48); } template<typename T> inline void read(T &x){ char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();} while('0'<=s&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();if(pd) x=-x; } } namespace IO{ template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);} inline void write(const char c){putchar(c);} inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);} template<typename T> inline void Write(T x){write(x);putchar(' ');} inline void Write(const char c){write(c);if(c!='\n') putchar(' ');} inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');} template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);} template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);} } using namespace IO; class HASH{ public: int HS[N]; inline void mk(char* s){For(i,0,strlen(s)-1,1) HS[i+1]=(1ll*HS[i]*P%MOD+s[i])%MOD;} inline int get(int l,int r){return (HS[r]-1ll*HS[l-1]*pw[r-l+1]%MOD+MOD)%MOD;} }ha[N],hb[N]; int main(){ #ifndef ONLINE_JUDGE freopen("in_out/in.in","r",stdin); freopen("in_out/out.out","w",stdout); #endif pw[0]=1; For(i,1,N-1,1) pw[i]=1ll*pw[i-1]*P%MOD; read(n,m); For(i,1,n,1) scanf("%s",ls),ha[i].mk(ls); For(i,1,n,1) scanf("%s",ls),hb[i].mk(ls); int l=1,r=1,cnt=0,ans=0x3f3f3f3f; while(r<=m){ cnt++; For(i,1,n,1) pd[ha[i].get(l,r)]=cnt; For(i,1,n,1) if(pd[hb[i].get(l,r)]==cnt){r++;goto End;} ans=min(ans,r-l+1); l++; End:; } write(ans); }
也可以二分答案。
-
「TJOI2018」str
考虑 \(dp\)
\(dp_{i,j}\) 表示枚举到第 \(i\) 个氨基酸,匹配到 \(j\) 位的方案数。
有转移:
\[dp{i,j}=\sum\limits_{k\in 可匹配的a_i碳基}dp[i-1][j-l_{i,k}] \]\(l_{i,k}\) 表示第 \(i\) 个氨基酸,第 \(k\) 个碳基的长度。
匹配直接 \(hash\) 判即可。
CODE
#include<bits/stdc++.h> using namespace std; typedef long long llt; typedef unsigned long long ull; const int N=1e5+3,MOD=1e9+7,MOD1=1000000123,MOD2=1000000321,P=131; #define For(i,a,b,c) for(register int $L=a,$R=b,$C=c,$D=(0<=$C)-($C<0),i=$L;i*$D<=$R*$D;i+=$C) int dp[102][N],n; char s[N],a[N]; struct DB{ int F,S; bool operator==(DB x)const{return x.F==F&&x.S==S;} DB operator+(DB x)const{return {(F+x.F)%MOD1,(S+x.S)%MOD2};} DB operator-(DB x)const{return {(F-x.F+MOD1)%MOD1,(S-x.S+MOD2)%MOD2};} DB operator*(DB x)const{return {1ll*F*x.F%MOD1,1ll*S*x.S%MOD2};} }pw[N]; namespace IO{ template<typename T> inline void write(T x){ static T st[45];T top=0;if(x<0)x=~x+1,putchar('-'); do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48); } template<typename T> inline void read(T &x){ char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();} while('0'<=s&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();if(pd) x=-x; } } namespace IO{ template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);} inline void write(const char c){putchar(c);} inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);} template<typename T> inline void Write(T x){write(x);putchar(' ');} inline void Write(const char c){write(c);if(c!='\n') putchar(' ');} inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');} template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);} template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);} } using namespace IO; class HASH{ public: DB HS[N]; inline void mk(char* s){For(i,0,strlen(s)-1,1) HS[i+1]=HS[i]*pw[1]+DB{s[i],s[i]};} inline DB get(int l,int r){return HS[r]-HS[l-1]*pw[r-l+1];} }cs,ca; int main(){ #ifndef ONLINE_JUDGE freopen("in_out/in.in","r",stdin); freopen("in_out/out.out","w",stdout); #endif pw[0]=DB{1,1}; For(i,1,N-1,1) pw[i]=pw[i-1]*DB{P,P}; read(n);scanf("%s",s+1);cs.mk(s+1); int len=strlen(s+1),ls;read(ls); For(i,1,ls,1){ scanf("%s",a+1);ca.mk(a+1); int l=strlen(a+1); For(j,l,len,1) if(cs.get(j-l+1,j)==ca.HS[l]) dp[1][j]=(dp[1][j]+1)%MOD; } For(k,2,n,1){ int x;read(x); For(i,1,x,1){ scanf("%s",a+1);ca.mk(a+1); int l=strlen(a+1); For(j,l,len,1) if(cs.get(j-l+1,j)==ca.HS[l]) dp[k][j]=(dp[k][j]+dp[k-1][j-l])%MOD; } } int ans=0; For(i,1,len,1) ans=(ans+dp[n][i])%MOD; write(ans); }
-
通配符匹配
依然 \(dp\)
\(dp_{i,j}=0/1\) 表示第 \(i\) 个通配符匹配到 \(j\) 是否成功。
对于每一个通配符分段,对于 \(?\) 直接转移,对于 \(*\) 枚举左端点 \(Hash\) 判断。
CODE
#include<bits/stdc++.h> using namespace std; typedef long long llt; typedef unsigned long long ull; const int N=1e5+3,MOD=1000000321,P=131; #define For(i,a,b,c) for(register int $L=a,$R=b,$C=c,$D=(0<=$C)-($C<0),i=$L;i*$D<=$R*$D;i+=$C) int pw[N],len[15],pos[15],tot_,n; char s[N],a[N]; bool dp[15][N],q[N]; namespace IO{ template<typename T> inline void write(T x){ static T st[45];T top=0;if(x<0)x=~x+1,putchar('-'); do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48); } template<typename T> inline void read(T &x){ char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();} while('0'<=s&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();if(pd) x=-x; } } namespace IO{ template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);} inline void write(const char c){putchar(c);} inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);} template<typename T> inline void Write(T x){write(x);putchar(' ');} inline void Write(const char c){write(c);if(c!='\n') putchar(' ');} inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');} template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);} template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);} } using namespace IO; class HASH{ public: int HS[N]; inline void mk(char* s){For(i,0,strlen(s)-1,1) HS[i+1]=(1ll*HS[i]*P%MOD+s[i])%MOD;} inline int get(int l,int r){return (HS[r]-1ll*HS[l-1]*pw[r-l+1]%MOD+MOD)%MOD;} }hs,ha; inline bool scmp(int ls,int rs,int la,int ra){return hs.get(ls,rs)==ha.get(la,ra)||rs<ls;} int main(){ #ifndef ONLINE_JUDGE freopen("in_out/in.in","r",stdin); freopen("in_out/out.out","w",stdout); #endif pw[0]=1; For(i,1,N-1,1) pw[i]=1ll*pw[i-1]*P%MOD; scanf("%s",s+1), strcat(s+1,string("?").c_str()), hs.mk(s+1); For(i,1,strlen(s+1),1) if(s[i]=='*'||s[i]=='?') pos[++tot_]=i,len[tot_]=i-pos[tot_-1]-1; read(n); while(n--){ scanf("%s",a+1), strcat(a+1,string("?").c_str()), ha.mk(a+1); memset(dp,0,sizeof dp); int alen=strlen(a+1); dp[0][0]=1; For(i,1,tot_,1){ memset(q,0,sizeof q); For(j,len[i],alen,1){ q[j]=(dp[i-1][j-len[i]]&&scmp(pos[i]-len[i],pos[i]-1,j-len[i]+1,j))||q[j-1]; // cout<<'q'<<' '<<q[j]<<' '<<dp[i-1][j-len[i]]<<' '<<pos[i]-len[i]<<' '<<pos[i]-1<<' '<<j-len[i]+1<<' '<<j<<' '<<q[j-1]<<endl; } For(j,len[i],alen,1){ if(s[pos[i]]=='?'){ if(j==len[i]) continue; dp[i][j]=(dp[i-1][j-len[i]-1]&&scmp(pos[i]-len[i],pos[i]-1,j-len[i],j-1)); // cout<<'x'<<' '<<j<<' '<<dp[i-1][j-len[i]-1]<<' '<<scmp(pos[i]-len[i],pos[i]-1,j-len[i],j-1)<<' '; // Write(pos[i]-len[i],pos[i]-1,j-len[i],j-1,'\n'); } else dp[i][j]=q[j]; // cout<<j<<' '<<dp[i][j]<<endl; } } if(dp[tot_][alen]) puts("YES"); else puts("NO"); } }
KMP
核心是 \(nxt\)(前缀 \(border\) 长度)
\(s\) 下标从 \(0\) 开始。
考虑递推。
首先 \(nxt_{i+1} - nxt_i \le 1\),因为最多就是扩展一个。
当 \(s[nxt_i]=s[i+1]\) 时,\(nxt_{i+1} = nxt_i\)
考虑 \(s[nxt_i]\not=s[i+1]\) 时,此时 \(nxt_{i+1}\) 的最大可能值就是 \(nxt_{nxt_i-1}\)
可以参考 oi-wiki
注意,为方便调用,实际使用时 \(nxt_i\) 其实存储在 \(i+1\) 处。
至于匹配,比较简单,就是在不相等时跳 \(nxt\),直接看代码吧(不建议使用 oi-wiki 上的匹配方法)。
核心代码
inline void Nxt(char *s){
int len=strlen(s),i=0,j=-1;
nxt[0]=-1;
For(i,0,len-1,1){
while(j!=-1&&s[i]!=s[j]) j=nxt[j];
if(s[i+1]==s[++j]) nxt[i+1]=nxt[j];
else nxt[i+1]=j;
}
}
scanf("%s%s",w,s);
Nxt(w);
int ans=0,j=0,lens=strlen(s),lenw=strlen(w);
For(i,0,lens-1,1){
while(~j&&w[j]!=s[i]) j=nxt[j]; j++;
if(j==lenw) j=nxt[j],ans++;
}
-
动物园
好像可以建树,但其实直接筛出 \(\le \frac{1}{2}size\) 的 \(border\) 长度再暴力跳即可。
CODE
#include<bits/stdc++.h> using namespace std; typedef long long llt; typedef unsigned long long ull; #define For(i,a,b,c) for(register int $L=a,$R=b,$C=c,$D=(0<=$C)-($C<0),i=$L;i*$D<=$R*$D;i+=$C) const int N=1e6+4,MOD=1000000007; int nxt[N],num[N],dp[N]; char s[N]; namespace IO{ template<typename T> inline void write(T x){ static T st[45];T top=0;if(x<0)x=~x+1,putchar('-'); do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48); } template<typename T> inline void read(T &x){ char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();} while('0'<=s&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();if(pd) x=-x; } } namespace IO{ template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);} inline void write(const char c){putchar(c);} inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);} template<typename T> inline void Write(T x){write(x);putchar(' ');} inline void Write(const char c){write(c);if(c!='\n') putchar(' ');} inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');} template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);} template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);} } using namespace IO; inline void Nxt(char *s){ int len=strlen(s),i=0,j=-1; nxt[0]=-1; while(i<len){ if(j==-1||s[i]==s[j]) nxt[++i]=++j; else j=nxt[j]; } } inline void Num(char *s){ int len=strlen(s),i=0,j=-1; num[0]=-1; while(i<len){ if(j==-1||s[i]==s[j]&&(j+1)<=((i+1)>>1)) num[++i]=++j; else j=nxt[j]; } } inline int Ans(int len){ For(i,1,len,1) dp[i]=dp[nxt[i]]+1; llt ans=1; For(i,1,len,1) ans=ans*(dp[num[i]]+1)%MOD; return ans; } int main(){ #ifndef ONLINE_JUDGE freopen("in_out/in.in","r",stdin); freopen("in_out/out.out","w",stdout); #endif int t;read(t); while(t--){ scanf("%s",s); Nxt(s),Num(s); // For(i,1,strlen(s),1) cout<<num[i]<<endl; Write(Ans(strlen(s)),'\n'); } }
-
Censoring
用栈存,该删时出栈,注意要存一下在 \(i\) 时 \(j\) 的位置。
CODE
#include<bits/stdc++.h> using namespace std; typedef long long llt; typedef unsigned long long ull; #define For(i,a,b,c) for(register int $L=a,$R=b,$C=c,$D=(0<=$C)-($C<0),i=$L;i*$D<=$R*$D;i+=$C) const int N=2e6+4; int nxt[N],pos[N]; string s,t; stack<int> sta; namespace IO{ template<typename T> inline void write(T x){ static T st[45];T top=0;if(x<0)x=~x+1,putchar('-'); do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48); } template<typename T> inline void read(T &x){ char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();} while('0'<=s&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();if(pd) x=-x; } } namespace IO{ template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);} inline void write(const char c){putchar(c);} inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);} template<typename T> inline void Write(T x){write(x);putchar(' ');} inline void Write(const char c){write(c);if(c!='\n') putchar(' ');} inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');} template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);} template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);} } using namespace IO; inline void Nxt(string s){ int len=s.size(),i=0,j=-1; nxt[0]=-1; while(i<len){ while(j!=-1&&s[i]!=s[j]) j=nxt[j]; if(s[++i]==s[++j]) nxt[i]=nxt[j]; else nxt[i]=j; } } int main(){ #ifndef ONLINE_JUDGE freopen("in_out/in.in","r",stdin); freopen("in_out/out.out","w",stdout); #endif cin>>s>>t; Nxt(t); int len=t.size(),j=0; For(i,0,s.size()-1,1){ sta.push(i); while(~j&&s[i]!=t[j]) j=nxt[j]; j++; pos[i]=j; if(j==len){ For(j,1,len,1) sta.pop(); if(sta.empty()) j=0; else j=pos[sta.top()]; } } stack<int> ls; while(!sta.empty()) ls.push(sta.top()),sta.pop(); while(!ls.empty()) write(s[ls.top()]),ls.pop(); }
-
OKR-Periods of Words
本质是求最小 \(border\) 长度。
求完最大 \(border\)(\(nxt\))后直接跳。
好像可以倍增,类似并查集优化,但本题都不用。
CODE
#include<bits/stdc++.h> using namespace std; typedef long long llt; typedef unsigned long long ull; #define For(i,a,b,c) for(register int $L=a,$R=b,$C=c,$D=(0<=$C)-($C<0),i=$L;i*$D<=$R*$D;i+=$C) const int N=2e6+4; int nxt[N],len,pos[N]; string s; stack<int> sta; namespace IO{ template<typename T> inline void write(T x){ static T st[45];T top=0;if(x<0)x=~x+1,putchar('-'); do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48); } template<typename T> inline void read(T &x){ char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();} while('0'<=s&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();if(pd) x=-x; } } namespace IO{ template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);} inline void write(const char c){putchar(c);} inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);} template<typename T> inline void Write(T x){write(x);putchar(' ');} inline void Write(const char c){write(c);if(c!='\n') putchar(' ');} inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');} template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);} template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);} } using namespace IO; inline void Nxt(string s){ int j=-1; nxt[0]=-1; For(i,0,len-1,1){ while(j!=-1&&s[i]!=s[j]) j=nxt[j]; nxt[i+1]=++j; } } inline llt Ans(){ llt ans=0; For(i,1,len,1){ int j=nxt[i]; while(pos[j]>0) j=pos[j]; pos[i]=j; if(j>0) ans+=(i-j); } return ans; } int main(){ #ifndef ONLINE_JUDGE freopen("in_out/in.in","r",stdin); freopen("in_out/out.out","w",stdout); #endif read(len),cin>>s; Nxt(s); write(Ans()); }
-
BZOJ1461字符串的匹配
好题。
用树状数组 \(log\) 求排名。
具体就是建值域的树状数组,求前缀和。
KMP 即可。
CODE
#include<bits/stdc++.h> using namespace std; typedef long long llt; typedef unsigned long long ull; #define For(i,a,b,c) for(register int i=a;i<=b;i+=c) #define For_(i,a,b,c) for(register int i=a;i>=b;i-=c) const int N=5e5+3; int nxt[N],s[N],t[N],crk[N],n,m,cs,ans,cans[N]; namespace IO{ template<typename T> inline void write(T x){ static T st[45];T top=0;if(x<0)x=~x+1,putchar('-'); do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48); } template<typename T> inline void read(T &x){ char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();} while('0'<=s&&s<='9'){x=(x<<1)+(x<<3)+(s^48),s=getchar();}if(pd) x=-x; } } namespace IO{ template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);} inline void write(const char c){putchar(c);} inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);} template<typename T> inline void Write(T x){write(x);putchar(' ');} inline void Write(const char c){write(c);if(c!='\n') putchar(' ');} inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');} template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);} template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);} } using namespace IO; class Btree{ private: int a[N]; inline int lowbit(int x){return x&(-x);} public: inline void Clr(){memset(a,0,sizeof a);} inline void Add(int x,int t){For(i,x,N-1,lowbit(i))a[i]+=t;} inline int Sum(int x){int s=0;For_(i,x,1,lowbit(i))s+=a[i];return s;} }bt; inline bool equ(int a,int b){ return a==bt.Sum(b-1); } inline void Nxt(){ int i=1,j=0,l=1; nxt[1]=0; while(i<=m){ while(l<=i-j) bt.Add(t[l++],-1); if(j&&!equ(crk[j],t[i])) j=nxt[j]; else bt.Add(t[i],1),nxt[++i]=++j; } bt.Clr(); } int main(){ #ifndef ONLINE_JUDGE freopen("in_out/in.in","r",stdin); freopen("in_out/out.out","w",stdout); #endif read(n,m,cs); For(i,1,n,1) read(s[i]); For(i,1,m,1) read(t[i]),bt.Add(t[i],1),crk[i]=bt.Sum(t[i]-1); bt.Clr(); Nxt(); int i=1,j=1,l=1; while(i<=n){ while(l<=i-j) bt.Add(s[l++],-1); if(j&&!equ(crk[j],s[i])) j=nxt[j]; else{ if(++j==m) cans[++ans]=l,j=nxt[j]; bt.Add(s[i++],1); } } write(ans,'\n'); For(i,1,ans,1) write(cans[i],'\n'); }
trie
挺简单的,感觉重点在 \(01trie\)
可以用于插入、查找字符串、前缀。
\(01trie\) 多用于在一个序列中找一个与一个数异或相同的,多组询问。
也可以求一个序列中两个数异或和中最大的(The XOR Largest Pair)。
做法就是按二进制建 \(trie\),查询时尽可能走不同的路径。
-
The XOR-longest Path
边 dfs 边加入,查询即可。
CODE
#include<bits/stdc++.h> using namespace std; typedef long long llt; typedef unsigned long long ull; #define For(i,a,b,c) for(register int i=a;i<=b;i+=c) #define For_(i,a,b,c) for(register int i=a;i>=b;i-=c) const int N=2e6+4; int n,z[33],ans=-1; struct edge{int t,v;}; vector<edge> to[N]; bool vis[N]; namespace IO{ template<typename T> inline void write(T x){ static T st[45];T top=0;if(x<0)x=~x+1,putchar('-'); do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48); } template<typename T> inline void read(T &x){ char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();} while('0'<=s&&s<='9'){x=(x<<1)+(x<<3)+(s^48),s=getchar();}if(pd) x=-x; } } namespace IO{ template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);} inline void write(const char c){putchar(c);} inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);} template<typename T> inline void Write(T x){write(x);putchar(' ');} inline void Write(const char c){write(c);if(c!='\n') putchar(' ');} inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');} template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);} template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);} } using namespace IO; inline void Fj(int x){For(i,1,31,1) z[i]=x%2,x/=2;} class Trie{ private: int t[N][3],tot_; public: inline void Add(){ int rt=0; For_(i,31,1,1){ if(!t[rt][z[i]]) t[rt][z[i]]=++tot_; rt=t[rt][z[i]]; } } inline int Get(){ int rt=0,sum=0; For_(i,31,1,1){ if(!t[rt][!z[i]]) rt=t[rt][z[i]]; else rt=t[rt][!z[i]],sum+=(1<<i-1); } return sum; } }tr; void dfs(int x,int t){ vis[x]=1; for(edge i:to[x]){ int y=i.t,v=i.v; if(vis[y]) continue; int ls=t^v; Fj(ls); ans=max(ans,tr.Get()); tr.Add(); dfs(y,t^v); } } int main(){ #ifndef ONLINE_JUDGE freopen("in_out/in.in","r",stdin); freopen("in_out/out.out","w",stdout); #endif read(n); For(i,1,n-1,1){int a,b,v;read(a,b,v),to[a].push_back({b,v}),to[b].push_back({a,v});} tr.Add(); dfs(1,0); write(ans); }
-
Nikitosh 和异或
首先考虑对于一段区间的异或和最大。
显然可以前缀异或,就变成了在区间中找两个数,使其异或和最大。
\(01trie\) 即可。
考虑本题。
可以先预处理处每个前缀和后缀的区间的最大异或和,枚举区间的分割点即可。
CODE
#include<bits/stdc++.h> using namespace std; typedef long long llt; typedef unsigned long long ull; #define For(i,a,b,c) for(register int i=a;i<=b;i+=c) #define For_(i,a,b,c) for(register int i=a;i>=b;i-=c) const int N=1e7+4; int n,a[N],bg[N],ed[N],ans=-1; namespace IO{ template<typename T> inline void write(T x){ static T st[45];T top=0;if(x<0)x=~x+1,putchar('-'); do{st[top++]=x%10;}while(x/=10);while(top)putchar(st[--top]^48); } template<typename T> inline void read(T &x){ char s=getchar();x=0;bool pd=false;while(s<'0'||'9'<s){if(s=='-') pd=true;s=getchar();} while('0'<=s&&s<='9'){x=(x<<1)+(x<<3)+(s^48),s=getchar();}if(pd) x=-x; } } namespace IO{ template<typename T,typename... Args> inline void read(T& x,Args&... args){read(x);read(args...);} inline void write(const char c){putchar(c);} inline void write(const char *c){int len=strlen(c);For(i,0,len-1,1) putchar(c[i]);} template<typename T> inline void Write(T x){write(x);putchar(' ');} inline void Write(const char c){write(c);if(c!='\n') putchar(' ');} inline void Write(const char *c){write(c);if(c[strlen(c)-1]!='\n') putchar(' ');} template<typename T,typename... Args> inline void write(T x,Args... args){write(x);write(args...);} template<typename T,typename... Args> inline void Write(T x,Args... args){Write(x);Write(args...);} } using namespace IO; class Trie{ private: int t[N][3],z[33],tot_; public: inline void Fj(int x){For(i,1,31,1) z[i]=(x&1),x>>=1;} inline void Clr(){memset(t,0,sizeof t),memset(z,0,sizeof z),tot_=0;} inline void Add(){ int rt=0; For_(i,32,1,1){ if(!t[rt][z[i]]) t[rt][z[i]]=++tot_; rt=t[rt][z[i]]; } } inline int Get(){ int rt=0,sum=0; For_(i,32,1,1){ if(!t[rt][!z[i]]) rt=t[rt][z[i]]; else rt=t[rt][!z[i]],sum+=(1<<i-1); } return sum; } }tr; int main(){ #ifndef ONLINE_JUDGE freopen("in_out/in.in","r",stdin); freopen("in_out/out.out","w",stdout); #endif read(n);tr.Add(); For(i,1,n,1) read(a[i]),a[i]^=a[i-1]; For(i,1,n,1) tr.Fj(a[i]),bg[i]=max(bg[i-1],tr.Get()),tr.Add(); tr.Clr(),tr.Add(); For_(i,n,1,1) tr.Fj(a[i]),ed[i]=max(ed[i+1],tr.Get()),tr.Add(); For(i,0,n,1) ans=max(ans,bg[i]+ed[i+1]); write(ans); }
本文来自博客园,作者:xrlong,转载请注明原文链接:https://www.cnblogs.com/xrlong/articles/17994975