bnu j just a string
求一个给定字符串中的由来自前缀集合和后缀集合构成的笛卡尔积中所有元素的魅力值的异或值。 (x,y)的魅力值为字符串x,y中的b的最大长度。 其中 字符串x=字符串a+字符串b 字符串y=字符串b+字符串c.
J. Just A String
Time Limit: 3000ms
Memory Limit: 262144KB
64-bit integer IO format: %lld Java class name: Main何老师手中有一个字符串,他发现这个字符串有一个神奇的性质,取出一个长为的前缀(就是由的前个字符顺序构成的字符串)和一个长为的后缀(就是由的后个字符顺序构成的字符串)之后,总是存在三个字符串使得,虽然这听起来像是一句废话。
显然三元组不总是唯一的,何老师从所有可能的三元组中找到最长的,很容易知道这样的三元组是唯一的,并且认为和的契合度就是,现在你需要帮何老师算出所有的异或和。
这里表示字符串的长度,表示将两个字符串和顺序拼接起来后得到的新字符串。
1 /* ____________________ 2 #include<bits/stdc++.h> 3 using namespace std; 4 typedef long long ll; 5 typedef pair<ll,ll> pll; 6 #define pb(x) push_back(x) 7 typedef unsigned long long ull; 8 #define mem(A, X) memset(A, X, sizeof A) 9 #define ford(i,l,u) for(ll (i)=(ll)(l);(i)>=(ll)(u);--(i)) 10 #define foreach(e,x) for(__typeof(x.begin()) e=x.begin();e!=x.end();++e) 11 #define fori(i,l,u) for(ll (i)=(ll)(l);(i)<=(ll)(u);++(i)) 12 typedef pair<int,int> pii; 13 #define mp make_pair 14 #define sec second 15 #define fir first 16 17 const ll mod=1e9+7; 18 const ll Maxn=2e3+10; 19 20 21 ll Next[Maxn]; 22 23 void GetNext(char *p,ll m) 24 { 25 Next[0]=Next[1]=0; 26 27 fori(i,1,m-1) 28 { 29 ll j=Next[i]; 30 while(j&&p[i]!=p[j]) j=Next[j]; 31 Next[i+1]= p[i]==p[j] ? j+1:0; 32 } 33 } 34 35 ll Common[Maxn]; 36 void Find(char *s,char *p,ll m) 37 { 38 GetNext(p,m); 39 ll n=strlen(s); 40 //fori (i,0,m-1) cout<<Next[i]<<" "; 41 //cout<<endl; 42 ll j=0; 43 //fori (i,0,m-1) printf("%d ",Next[i]); 44 //printf("\n j: "); 45 fori (i,0,n-1) { 46 while(j&&s[i]!=p[j]) j=Next[j]; 47 if(s[i]==p[j]) j++; 48 49 //printf("__%d i-j+1: %d ",j,i-j+1); 50 if(j==0) Common[i]=0; 51 else Common[i]=j; 52 if(j==m) j=Next[j];// 排除越界访问。 53 } 54 //puts(""); 55 } 56 57 58 int main() 59 { 60 std::ios::sync_with_stdio(false); 61 //freopen("in.txt","r",stdin); 62 int T; 63 while(scanf("%d",&T) != EOF) 64 { 65 char s[Maxn]; 66 scanf("%s",s); 67 ll n = strlen(s); 68 ll ret=0; 69 fori (j,1,n) { 70 fori(di,0,n-1) Common[di]=0; 71 Find(s, s + (n-j), j); 72 //printf("%s___\n",s + (n - j )); 73 // fori (di, 0, n-1) printf("%d ",Common[di]); 74 // puts(""); 75 //puts(""); 76 fori (id, 0, n-1) { 77 ll A,B,C,i; 78 B = Common[id]; 79 i=id+1; 80 A = i - B; 81 C = j - B; 82 ll temp = A * B * B * C; 83 //cout<<"A B C:"<<A<<" "<<B<<" "<<C<<" temp: "<<temp<<endl; 84 //cout<<temp<<endl; 85 ret= ret ^ temp; 86 } 87 } 88 printf("%lld\n",ret); 89 } 90 return 0; 91 } 92 93 /*__________ 94 analysis: 分析考虑每个f(i,j)的含义,其含义与kmp算法中next数组几乎一致,只是细节上一个下标还有一些对应关系的差别。 之后就是考虑快速得到所有的f值, 95 枚举每一个后缀sufj,对sufj和完整的文本串进行匹配。由于sufj为后缀,即可确定f()中固定的j,而对于sufj和完整文本串匹配的时候,某个Nexti值就确定出来了后缀j与前缀i(后缀j指文本串的下标j,j+1,... n-1 构成的后缀,同理prei)的魅力值。回顾某个确定的后缀j会发现,j是和所有的i=0 1 2 3 ... n-1 一一对应的,所以只需要枚举所有的后缀均和文本串进行一次kmp即可。 96 debug : 实现的时候,因为是枚举后缀,使用的指针传下标结合模式串的个数的形式,在求next数组的时候要及时在某次匹配完一次完整的模式串时更新下次带检测的位置,不然会由于超出去的位置有字符引起匹配错误。 97 note : 98 */