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

何老师手中有一个字符串S,他发现这个字符串有一个神奇的性质,取出一个长为i的前缀(就是由S的前i个字符顺序构成的字符串)pre_i和一个长为j的后缀(就是由S的后j个字符顺序构成的字符串)suf_j之后,总是存在三个字符串A,B,C使得pre_i=A+B,suf_j=B+C,虽然这听起来像是一句废话

显然三元组A,B,C不总是唯一的,何老师从所有可能的三元组中找到B最长的,很容易知道这样的三元组是唯一的,并且认为pre_isuf_j的契合度就是f(i,j)=|A||B|^2|C|,现在你需要帮何老师算出所有f(i,j)(0 \leq i,j \leq n)的异或和。

这里|X|表示字符串X的长度,X+Y表示将两个字符串XY顺序拼接起来后得到的新字符串。
 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   */ 

 

posted @ 2017-04-29 01:09  TechIsOnlyTool  阅读(404)  评论(0编辑  收藏  举报