• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            poj 3764 The xor-longest Path 字典樹 + Xor

               這題意思很簡單。求一棵樹里面的一條路徑,使得其異或權(quán)(就是將路徑里面所有邊的權(quán)值異
            或起來)最大。
               這個題有兩步。第一步是假定根為節(jié)點0,求出根到其它節(jié)點的異或距離,保存在數(shù)組xor里面,
            這個dfs一下即可。然后,用xor[i]^xor[j]就能代表節(jié)點i到節(jié)點j的路徑。這個結(jié)論可以這么看。
            如果,i和j之間的路徑經(jīng)過根節(jié)點,那么上面的結(jié)論肯定是正確的。如果,該路徑不經(jīng)過根,那么
            xor[i]和xor[j]必定保護從根到某個節(jié)點的相同的一段子路徑,根據(jù)異或的性質(zhì),這段子路徑會
            被消掉,所以這個結(jié)論也是這確的。。。
               第二步就是枚舉,xor[i]^xor[j]使得結(jié)果最大了。如果直接暴力,平方的算法肯定會超時的。
            由于每個值可以表示成2進制,如果把其它xor值都保存在字典樹里面,用當前的xor[i]去字典樹
            里面,一遍就可以找到異或最大值。
               另外,由于樹的點數(shù)太多,只能用鄰接表,用vector模擬鄰接表果斷超時了。。。
            改成靜態(tài)鏈表才過。。。

               代碼如下:
            #include <stdio.h>
            #include <string.h>
            #include <algorithm>
            #include <vector>
            using namespace std;

            const int MAX = 100010;
            int nXor[MAX];
            bool bVis[MAX];
            int nFirst[MAX];
            struct Edge
            {
                int nE;
                int nW;
                int nNext;
            };
            Edge egs[MAX * 2];

            struct Node
            {
                Node* pSons[2];
            };
            Node nodes[MAX * 32];
            Node* pRoot = &nodes[0];
            int nNew;

            void GetBCode(int nL, int* nBCode, int& nLen)
            {
                nLen = 0;
                while (nLen <= 30)
                {
                    nBCode[nLen++] = nL % 2;
                    nL >>= 1;
                }
                reverse(nBCode, nBCode + nLen);
            }

            void Insert(int nL)
            {
                int nLen = 0;
                int i = 0;
                int nBCode[32];

                GetBCode(nL, nBCode, nLen);
                Node* pNode = pRoot;

                while (i < nLen)
                {
                    if (pNode->pSons[nBCode[i]])
                    {
                        pNode = pNode->pSons[nBCode[i]];
                    }
                    else
                    {
                        memset(nodes + nNew, 0, sizeof(nodes[nNew]));
                        pNode->pSons[nBCode[i]] = nodes + nNew;
                        pNode = nodes + nNew;
                        ++nNew;
                    }
                    ++i;
                }
            }

            int FindMax(int nL)
            {
                int nLen = 0;
                int nAns = 0;
                int i = 0;
                int nBCode[32];
                Node* pNode = pRoot;
                
                GetBCode(nL, nBCode, nLen);
                while (i < nLen)
                {
                    int nBest = (nBCode[i] == 0 ? 1 : 0);
                    int nBad = (nBCode[i] == 0 ? 0 : 1);
                    if (pNode->pSons[nBest])
                    {
                        nAns = 2 * nAns + nBest;
                        pNode = pNode->pSons[nBest];
                    }
                    else if (pNode->pSons[nBad])
                    {
                        nAns = 2 * nAns + nBad;
                        pNode = pNode->pSons[nBad];
                    }
                    else break;
                    ++i;
                }

                return nAns ^ nL;
            }

            void Dfs(int nV, int nL)
            {
                nXor[nV] = nL;
                bVis[nV] = true;
                for (int e = nFirst[nV]; e != -1; e = egs[e].nNext)
                {
                    if (!bVis[egs[e].nE])
                    {
                        Dfs(egs[e].nE, nL ^ egs[e].nW);
                    }
                }
            }

            int main()
            {
                int nN;
                int nU, nV, nW;
                
                while (scanf("%d", &nN) == 1)
                {
                    for (int i = 0; i < nN; ++i) nFirst[i] = -1;
                    for (int i = 1, j = 0; i < nN; ++i)
                    {
                        scanf("%d%d%d", &nU, &nV, &nW);
                        egs[j].nE = nV;
                        egs[j].nW = nW;
                        egs[j].nNext = nFirst[nU];
                        nFirst[nU] = j++;
                        egs[j].nE = nU;
                        egs[j].nW = nW;
                        egs[j].nNext = nFirst[nV];
                        nFirst[nV] = j++;
                    }

                    memset(bVis, falsesizeof(bool) * nN);
                    Dfs(0, 0);

                    memset(&nodes[0], 0, sizeof(Node));
                    nNew = 1;
                    int nAns = 0;
                    
                    for (int i = 0; i < nN; ++i)
                    {
                        nAns = max(nAns, FindMax(nXor[i]));
                        Insert(nXor[i]);
                    }
                    printf("%d\n", nAns);
                }

                return 0;
            }

            posted @ 2012-10-12 20:12 yx 閱讀(1023) | 評論 (0)編輯 收藏

            poj 1182 食物鏈 并查集

               這是并查集最后一題,據(jù)說也是最經(jīng)典的一題。經(jīng)常前面幾題的訓練,這題的思路很快
            就能想出來了。只需要對每個節(jié)點附加一個信息表示離根節(jié)點的距離,并且距離是模3循環(huán)的。
               注意合并時候保持距離變化的正確性。而且合并有2種情況,距離相同合并和距離不同合并。
            分別對應(yīng)于題目描述中的1和2操作。
               關(guān)鍵還是FindSet里面對距離nDis數(shù)組里面的修改,前面一直寫錯這個,wa了好幾次,還是
            看隊友代碼才一眼發(fā)現(xiàn)我又把這里寫錯了。。。當前距離的更新還是等于當前距離加上前一個
            節(jié)點的距離再模3,類似于前面幾題的更新方法。
               這種將有關(guān)系的節(jié)點放在一個并查集里面,再給每個節(jié)點附加其它信息描述其它關(guān)系的做法,
            確實比較有效。。。并查集是應(yīng)用于不相交集合的數(shù)據(jù)結(jié)構(gòu),看來某個時候卻有妙用啊。。。

               代碼如下:
            #include <stdio.h>
            #include <string.h>
            #include <algorithm>
            using namespace std;

            const int MAX = 50010;
            int nN, nK;
            int nSets[MAX];
            int nDis[MAX];

            void MakeSets(int nN)
            {
                for (int i = 1; i <= nN; ++i)
                {
                    nSets[i] = i;
                    nDis[i] = 0;
                }
            }

            int FindSet(int nI)
            {
                if (nSets[nI] != nI)
                {
                    int nPre = nSets[nI];
                    nSets[nI] = FindSet(nSets[nI]);
                    nDis[nI] = (nDis[nPre] + nDis[nI]) % 3;
                }
                return nSets[nI];
            }

            int main()
            {
                int nAns = 0;
                int nOper, nX, nY;
                
                scanf("%d%d", &nN, &nK);
                MakeSets(nN);
                while (nK--)
                {
                    scanf("%d%d%d", &nOper, &nX, &nY);
                    if (nX > nN || nY > nN || nOper == 2 && nX == nY)
                    {
                        ++nAns;
                    }
                    else
                    {
                        if (nOper == 1)
                        {
                            int nA = FindSet(nX);
                            int nB = FindSet(nY);
                            if (nA == nB)
                            {
                                if (nDis[nX] != nDis[nY])
                                {
                                    ++nAns;
                                }
                            }
                            else
                            {
                                nSets[nB] = nA;
                                nDis[nB] = (nDis[nX] - nDis[nY] + 3) % 3;
                            }
                        }
                        else
                        {
                            int nA = FindSet(nX);
                            int nB = FindSet(nY);
                            if (nA == nB)
                            {
                                if ((nDis[nX] + 1) % 3 != nDis[nY])
                                {
                                    ++nAns;
                                }
                            }
                            else
                            {
                                nSets[nB] = nA;
                                nDis[nB] = (nDis[nX] + 1 - nDis[nY] + 3) % 3;
                            }
                        }
                    }
                }
                printf("%d\n", nAns);

                return 0;
            }

               

            posted @ 2012-10-10 20:51 yx 閱讀(1271) | 評論 (0)編輯 收藏

            poj 1988 Cube Stacking 并查集

               也是個題意比較奇葩的題目。有2個操作,1個是把一個元素所在的棧,放到另外1個元素所在
            的棧上面。另外一個操作是統(tǒng)計某個元素下面有多少個元素(當然是在同一個棧中)。
               貌似,需要記錄每個元素下面的元素是什么了,既然要記錄這個就不能用并查集的路徑壓縮了。
             不壓縮路徑的話,肯定會超時的。怎么辦了。。。
               其實,可以這么考慮,以每個棧的棧底元素作為并查集的代表元素。壓縮路徑后,每個元素或者
            是根元素或者其父親元素就是根元素。所以,另外對每個節(jié)點附加個信息代表該節(jié)點的高度,棧底
            元素高度為0。再附加個信息代表每個并查集元素總數(shù)目,這樣就可以在合并集合時候修改信息,
            并且壓縮路徑也能保證答案正確。。。

               代碼如下:
            #include <stdio.h>
            #include <stdlib.h>
            #include <string.h>
            #include <algorithm>
            using namespace std;

            const int MAX = 30010;
            int nSets[MAX];
            int nNum[MAX];
            int nRank[MAX];

            void MakeSets(int nN)
            {
                for (int i = 0; i < nN; ++i)
                {
                    nSets[i] = i;
                    nNum[i] = 1;
                    nRank[i] = 0;
                }
            }

            int FindSet(int nI)
            {
                if (nSets[nI] != nI)
                {
                    int nPre = nSets[nI];
                    nSets[nI] = FindSet(nSets[nI]);
                    nRank[nI] += nRank[nPre];
                }
                
                return nSets[nI];
            }

            void Move(int nX, int nY)
            {
                int nA = FindSet(nX);
                int nB = FindSet(nY);
                //printf("nA:%d,nB:%d\n", nA, nB);
                if (nA != nB)
                {
                    nSets[nA] = nB;
                    nRank[nA] += nNum[nB];
                    nNum[nB] += nNum[nA];
                }
            }

            int main()
            {
                int nP;
                char szOper[10];
                int nX, nY;

                scanf("%d", &nP);
                MakeSets(MAX);
                while (nP--)
                {
                    scanf("%s", szOper);
                    if (szOper[0] == 'M')
                    {
                        scanf("%d%d", &nX, &nY);
                        Move(nX, nY);
                    }
                    else
                    {
                        scanf("%d", &nX);
                        FindSet(nX);
                        printf("%d\n", nRank[nX]);
                    }
                }

                return 0;
            }

            posted @ 2012-10-10 12:15 yx 閱讀(968) | 評論 (0)編輯 收藏

            poj 1984 Navigation Nightmare 并查集

               并查集應(yīng)用的變形。題目意思是一個圖中,只有上下左右四個方向的邊。給出這樣的一些邊,
            求任意指定的2個節(jié)點之間的距離。
               有可能當前給出的信息,沒有涉及到要求的2個節(jié)點,或者只涉及到了1個節(jié)點,那么肯定
            無法確定它們的距離。或者根據(jù)已經(jīng)給出的邊只知道這2個節(jié)點在不同的聯(lián)通分量里面,那么其
            距離也是無法確定的,根據(jù)題目要求,輸出-1。
               問題是如果能夠確定它們在一個聯(lián)通分量里面,如何確定它們的距離了。
               這個題的關(guān)鍵在于,只有上下左右四個方向的邊,假設(shè)每個節(jié)點都有一個坐標的話,那么它們
            相對于代表該聯(lián)通分量節(jié)點的坐標肯定是固定的,那么就不需要考慮圖里面有環(huán)之類的情況了。
            這樣就可以很方便的應(yīng)用并查集來解了。
               利用并查集,給每個節(jié)點附加其它信息,即相對于代表該并查集的節(jié)點的坐標(x,y)。
            在FindSet里面求出坐標,在UnionSet里面修改合并后新加入的另外一個集合的根節(jié)點的坐標即可。
               代碼如下:

            #include <stdio.h> 
            #include <string.h>
            #include <stdlib.h>
            #include <algorithm>
            using namespace std;

            const int MAX_N = 40010;
            int nN, nM;
            int nSets[MAX_N];
            int nX[MAX_N];
            int nY[MAX_N];
            char szInput[MAX_N][100];

            void MakeSets(int nNum)
            {
                for (int i = 0; i < nNum; ++i)
                {
                    nSets[i] = i;
                    nX[i] = nY[i] = 0;
                }
            }

            int FindSets(int nI)
            {
                if (nSets[nI] != nI)
                {
                    int nPre = nSets[nI];
                    nSets[nI] = FindSets(nSets[nI]);
                    nX[nI] += nX[nPre];
                    nY[nI] += nY[nPre];
                }
                return nSets[nI];
            }

            void UnionSets(int nBeg, int nEnd, int dx, int dy)
            {
                int nA = FindSets(nBeg);
                int nB = FindSets(nEnd);
                if (nA != nB)
                {
                    nSets[nB] = nA;//把集合B合并到集合A中
                    nX[nB] = nX[nBeg] + dx - nX[nEnd];//因為方向逆過來了,所以是減去
                    nY[nB] = nY[nBeg] + dy - nY[nEnd];
                }
            }

            int main()
            {
                int nBeg, nEnd, nL;
                char szDir[10];

                while (scanf("%d%d%*c", &nN, &nM) == 2)
                {
                    MakeSets(nN);
                    for (int i = 0; i < nM; ++i)
                    {
                        fgets(szInput[i], 100, stdin);
                    }
                    int nK;
                    int nF1, nF2, nI;
                    scanf("%d", &nK);
                    int nCur = 0;
                    while (nK--)
                    {
                        scanf("%d%d%d", &nF1, &nF2, &nI);
                        for (int i = nCur; i < nI; ++i)
                        {
                            sscanf(szInput[i], "%d%d%d%s", &nBeg,
                                   &nEnd, &nL, szDir);
                            int dx = 0, dy = 0;
                            switch (szDir[0])
                            {
                                case 'N': dy += nL; break;
                                case 'S': dy -= nL; break;
                                case 'E': dx += nL; break;
                                case 'W': dx -= nL; break;
                            }
                            UnionSets(nBeg, nEnd, dx, dy);
                        }
                        nCur = nI;
                        
                        if (FindSets(nF1) != FindSets(nF2))
                        {
                            printf("-1\n");
                        }
                        else
                        {
                            printf("%d\n", abs(nX[nF1] - nX[nF2])
                                    + abs(nY[nF1] - nY[nF2]));
                        }
                    }
                }

                return 0;
            }

            posted @ 2012-10-09 21:25 yx 閱讀(949) | 評論 (0)編輯 收藏

            poj 1703 Find them, Catch them 并查集

               并查集應(yīng)用的變形。
               給出的是2個節(jié)點是敵對關(guān)系的信息,最后詢問任意2個節(jié)點的關(guān)系。根據(jù)這些信息,
            節(jié)點之間可能是敵對的,也可能不是的(因為敵人的敵人就是朋友),也可能給出的
            信息根本描述不了它們的關(guān)系。
               看起來跟原始的并查集應(yīng)用差遠了。。。
               有個比較直接的做法,那么就是把不在一個集合的節(jié)點直接用并查集合并在一起。這樣的話,
            如果詢問的2個節(jié)點在同一個并查集里面,那么它們之間的關(guān)系是確定的,否則無法確定它們的
            關(guān)系。
               現(xiàn)在還有一個問題是,在同一個并查集里面的2個節(jié)點是敵對關(guān)系還是朋友關(guān)系。。。
               可以給每個節(jié)點另外附加個信息,記錄其距離并查集根節(jié)點的距離。如果,詢問的2個節(jié)點距離
            其根節(jié)點的距離都是奇數(shù)或者都是偶數(shù),那么這2個節(jié)點是朋友關(guān)系,否則是敵對關(guān)系。。。

               代碼如下:
            #include <stdio.h>
            #include <string.h>
            #include <algorithm>
            using namespace std;

            const int MAX_N = 100010;
            int nSets[MAX_N];
            int nDis[MAX_N];

            int nN, nM;

            void MakeSets(int nNum)
            {
                for (int i = 0; i < nNum; ++i)
                {
                    nSets[i] = i;
                    nDis[i] = 0;
                }
            }

            int FindSet(int nI)
            {
                if (nSets[nI] != nI)
                {
                    int nPre = nSets[nI];
                    nSets[nI] = FindSet(nSets[nI]);
                    nDis[nI] = (nDis[nI] + nDis[nPre]) % 2;
                }
                return nSets[nI];
            }

            void UnionSet(int nI, int nJ)
            {
                int nA = FindSet(nI);
                int nB = FindSet(nJ);
                if (nA != nB)
                {
                    nSets[nA] = nB;
                    nDis[nA] = (nDis[nI] + nDis[nJ] + 1) % 2;
                }
            }

            int main()
            {
                int nT;
                
                scanf("%d", &nT);
                while (nT--)
                {
                    scanf("%d%d", &nN, &nM);
                    MakeSets(nN);
                    char szOper[10];
                    int nA, nB;
                    while (nM--)
                    {
                        scanf("%s%d%d", szOper, &nA, &nB);
                        if (szOper[0] == 'D')
                        {
                            UnionSet(nA, nB);
                        }
                        else
                        {
                            int nX = FindSet(nA);
                            int nY = FindSet(nB);
                            if (nX == nY)
                            {
                                if (nDis[nA] == nDis[nB])
                                {
                                    printf("In the same gang.\n");
                                }
                                else
                                {
                                    printf("In different gangs.\n");
                                }
                            }
                            else
                            {
                                printf("Not sure yet.\n");
                            }
                        }
                    }
                }
                
                return 0;
            }

            posted @ 2012-10-08 22:33 yx 閱讀(1106) | 評論 (0)編輯 收藏

            poj 1006 Biorhythms 中國剩余定理

               此題本來模擬即可,但是注意有容易出錯的地方。
               這題主要是可以用中國剩余定理來做。
               根據(jù)題意可以抽象出這樣的模型。給出三個數(shù)A,B,C分別是模23,28,33后的余數(shù),求最小的數(shù)字
            使得其模23,28,33分別為A,B,C,并且要大于給定的數(shù)字D。
               中國剩余定理很好的解決了這種余數(shù)問題。令模數(shù)為Ni,余數(shù)為Ai,設(shè)Mi = N1*N2*...*Ni-1*Ni+1*...*Nn,
            那么答案一定滿足形式ans = ΣAi*Mi*(Mi對Ni的乘法逆) % N。(N為所有Ni的乘積)。
               很明顯,由于ans的第i項有Mi因子,所以模N1-Ni-1和Ni+1-Nn肯定是0,而Ai*Mi*(Mi對Ni的乘法逆) %Ni
            就是Ai。這樣就滿足了要求。
               代碼如下:
            #include <stdio.h>
            #include <algorithm>
            #include <string.h>
            #include <vector>
            using namespace std;

            int Egcd(int nN, int nM, int& nX, int& nY)
            {
                if (nM == 0)
                {
                    nX = 1, nY = 0;
                    return nN;
                }
                int nRet = Egcd(nM, nN % nM, nX, nY);
                int nT = nX;
                nX = nY;
                nY = nT - (nN / nM) * nY;
                return nRet;
            }

            int main()
            {
                int nA, nB, nC, nD;
                int nDays = 21252;
                int nCase = 1;
                
                while (scanf("%d%d%d%d", &nA, &nB, &nC, &nD),
                       nA != -1 || nB != -1 || nC != -1 || nD != -1)
                {
                    int nFirst = 0;
                    nA %= 23;
                    nB %= 28;
                    nC %= 33;
                    int nM1= 28 * 33, nM2 = 23 * 33, nM3 = 23 * 28;
                    int nN1, nN2, nN3, nTemp;
                    Egcd(23, nM1, nTemp, nN1);
                    Egcd(28, nM2, nTemp, nN2);
                    Egcd(33, nM3, nTemp, nN3);
                    nFirst = (nA * nM1 * nN1 + nB * nM2 * nN2 + nC * nM3 * nN3) % nDays;
                    while (nFirst <= nD)nFirst += nDays;
                    printf("Case %d: the next triple peak occurs in %d days.\n",
                           nCase++, nFirst - nD);
                }
                
                return 0;
            }

            posted @ 2012-10-03 23:11 yx 閱讀(862) | 評論 (0)編輯 收藏

            poj 2406 Power Strings kmp的妙用

               這個題是求一個字符串的最小重復單元的重復次數(shù),那么求出最小重復單元的長度即可。
               這個題有3種方法,方法一:直接枚舉長度為[1,len/2]內(nèi)的子串,暴力就過了。方法二:
            將原串重復一次形成一個新串,用原串去匹配新串,但是得從第二個位置開始匹配,第一次
            成功匹配的位置減一就代表最小重復單元的長度。方法三:利用kmp的next函數(shù),如果len
            能夠整除len-next[len],那么len-next[len]就代表最小重復單元的長度。
               方法一明顯是對的,數(shù)據(jù)不強的情況下就能水過了。方法二也不是那么容易想到的,不過
            將原串擴展為2倍的做法也不是太奇葩,比如判斷2個循環(huán)串是否相等就可以用這個辦法做。
            方法三就比較難理解了。
               方法三的理解:
               next[len]代表的是str的最長前綴(使得這個前綴與同樣長度的后綴相等)的長度。所謂的next
            數(shù)組就是長度為1-len的str的滿足上述描述的最長前綴的長度。如果len是len-next[len]的倍數(shù),
            假設(shè)m = len-next[len] ,那么str[1-m] = str[m-2*m],以此類推下去,m肯定是str的最小
            重復單元的長度。假如len不是len-next[len]的倍數(shù), 如果前綴和后綴重疊,那么最小重復單元
            肯定str本身了,如果前綴和后綴不重疊,那么str[m-2*m] != str[len-m,len],所以str[1-m]
            != str[m-2*m] ,最終肯定可以推理出最小重復單元是str本身,因為只要不斷遞增m證明即可。
               
               方法三的代碼如下:
            #include <stdio.h>
            #include <string.h>
            #include <algorithm>
            using namespace std;

            char szStr[1000010];
            int nNext[1000010];

            void GetNext(char* szStr, int nLen, int* nNext)
            {
                nNext[0] = -1;
                for (int i = 1, j = -1; i < nLen; ++i)
                {
                    while (j > -1 && szStr[i] != szStr[j + 1])
                    {
                        j = nNext[j];
                    }
                    if (szStr[i] == szStr[j + 1])
                    {
                        ++j;
                    }
                    nNext[i] = j;
                }
            }

            int main()
            {
                while (scanf("%s", szStr), strcmp(szStr, "."))
                {
                    int nLen = strlen(szStr);
                    
                    GetNext(szStr, nLen, nNext);
                    if (nLen % (nLen - nNext[nLen - 1] - 1))
                    {
                        printf("1\n");
                    }
                    else
                    {
                        printf("%d\n", nLen / (nLen - nNext[nLen - 1] - 1));
                    }
                }
                
                return 0;
            }

               
               

            posted @ 2012-09-30 15:25 yx 閱讀(1300) | 評論 (1)編輯 收藏

            poj 3461 Oulipo Rabin-Karp 字符串匹配

               裸的字符串匹配,子串最長10,000,母串最長1,000,000。
               求子串在母串中出現(xiàn)的次數(shù)。
               如果子串長度較小,那么直接RK匹配即可,hash值相同時候,直接比較字符串是否相同。
            但是這個題的子串太長了,還比較字符串會超時,如果不比較字符串理論上是錯誤的,雖然
            出錯的概率很小,而且概率還是跟模數(shù)的選擇以及運算時候是否溢出有關(guān)。
               剛開始用了int,發(fā)現(xiàn)一直wa了,估計就是運算時候就超int了,取模沒起到作用。模數(shù)的選
            擇能夠提高正確率。Rabin-Karp 字符串匹配雖然比較好寫,也很容易理解,但是適用情況感
            覺不是很廣,比如子串太長了,處理就麻煩了,舍棄子串比較也不是很好。
               但是子串不長的話,Rabin-Karp 字符串匹配還是很不錯的。
               相比而言,這個題用kmp應(yīng)該會好很多。

               代碼如下:
            #include <stdio.h> 
            #include <string.h>
            #include <algorithm>
            using namespace std;

            typedef long long INT;
            char szStrM[1000010];
            char szStrS[10010];
            const INT MOD = 16381 * 4733 + 1;

            int main()
            {
                int nT;
                
                scanf("%d", &nT);
                while (nT--)
                {
                    scanf("%s%s", szStrS, szStrM);
                    INT nMatch = szStrS[0] - 'A';
                    INT nPowN = 1;
                    int nSizeS = 1;
                    char* pszStr = szStrS + 1;
                    while (*pszStr)
                    {
                        nMatch = (26 * nMatch + *pszStr - 'A') % MOD;
                        nPowN = (nPowN * 26) % MOD;
                        ++nSizeS;
                        ++pszStr;
                    }
                    //prINTf("match:%d\n", nMatch);
                    
                    int nSizeM = strlen(szStrM);
                    INT nKey = 0;
                    for (int i = 0; i < nSizeS; ++i)
                    {
                        nKey = (26 * nKey + szStrM[i] - 'A') % MOD;
                    }
                    //prINTf("key:%d\n", nKey);
                    
                    int nAns = 0;
                    for (int i = 0; i <= nSizeM - nSizeS; ++i)
                    {
                        //prINTf("key:%d\n", nKey);
                        if (nKey == nMatch)
                           // && memcpy(szStrS, szStrM + i, nSizeS) == 0)
                        {
                            ++nAns;
                        }
                        nKey = (26 * (nKey - nPowN * (szStrM[i] - 'A')) % MOD
                                + szStrM[i + nSizeS] - 'A') % MOD;
                        nKey = (nKey + MOD) % MOD;
                    }
                    
                    printf("%d\n", nAns);
                }
                
                return 0;
            }

            posted @ 2012-09-28 12:01 yx 閱讀(1120) | 評論 (0)編輯 收藏

            poj 1200 Crazy Search 字符串hash

               這個題是求一個字符串里面出現(xiàn)了多少個長度為N的不同子串,同時給出了母串里面不同字符
            的個數(shù)NC。
               保存子串到set里面直接暴力肯定超時了。這個題有個利用字符串hash的解法,雖然理論上有
            bug,但是能過這個題。
               利用給出的NC,對長度為N的字符串,將其當作NC進制的數(shù)字,求出其值,對值進行hash,
            求出不同的hash位置個數(shù)。
               這個算法其實類似于Karp-Rabin字符串匹配算法。不過,Karp-Rabin算法做了點改進,對
            進制為D的字符串求值的時候為了防止溢出會模一個素數(shù),而且不會每次都迭代求下一個子串的
            值,而是從當前子串的值直接遞推出下一個字符的值。怎么遞推了,其實很簡單,就是當前值去
            掉最高位再乘以D(相當于左移一位,不過是D進制的,不能直接用<<符號),再加上新的最低位。
               Karp-Rabin算法應(yīng)該主要在于設(shè)計出合理的hash算法,比如,用取模hash函數(shù)的話,得保
            證hash表足夠大,否則沖突太多,速度就不會怎么好了。比如這個題,hash表小了就AC不了了。

               代碼如下:
            #include <stdio.h>
            #include <string.h>

            const int MAX = 13747347;
            int nHash[MAX];
            char szStr[17000001];
            int nN, nNC;
            int nW[200];

            void Insert(int nKey)
            {
                int nPos = nKey;
                while (nHash[nPos] != -1 && nHash[nPos] != nKey)
                {
                    nPos = (nPos + 1) % MAX;
                }
                nHash[nPos] = nKey;
            }

            bool Find(int nKey)
            {
                int nPos = nKey;
                while (nHash[nPos] != -1 && nHash[nPos] != nKey)
                {
                    nPos = (nPos + 1) % MAX;
                }
                return nHash[nPos] != -1;
            }

            int main()
            {
                while (scanf("%d%d%s", &nN, &nNC, szStr) == 3)
                {
                    memset(nW, 0, sizeof(nW));
                    memset(nHash, -1, sizeof(nHash));
                    int nNum = 0;
                    int nSize = 0;
                    for (char* pszStr = szStr; *pszStr; ++pszStr)
                    {
                        if (!nW[*pszStr])
                        {
                            nW[*pszStr] = ++nNum;
                        }
                        ++nSize;
                    }

                    int nKey = 0;
                    int nAns = 0;
                    int nPowN = 1;
                    for (int j = 0; j < nN; ++j)
                    {
                        nKey = (nKey * nNC + nW[szStr[j]]) % MAX;
                        nPowN *= nNC;
                    }
                    nPowN /= nNC;
                    if (!Find(nKey))
                    {
                        Insert(nKey);
                        nAns++;
                    }
                    
                    for (int i = nN; i < nSize; ++i)
                    {
                        nKey = (nNC * (nKey - nPowN * nW[szStr[i - nN]])
                                + nW[szStr[i]]) % MAX;
                        nKey = (nKey + MAX) % MAX;
                        
                        if (!Find(nKey))
                        {
                            Insert(nKey);
                            nAns++;
                        }
                    }
                    
                    printf("%d\n", nAns);
                }

                return 0;
            }

            posted @ 2012-09-27 22:07 yx 閱讀(1041) | 評論 (0)編輯 收藏

            poj 1811 Prime Test 數(shù)論 素數(shù)測試

             代碼如下:
            #include <stdio.h>
            #include <time.h>
            #include <math.h>
            #include <stdlib.h>
            #include <algorithm>
            using namespace std;
            typedef unsigned long long LL;
            #define MAX (5000000)
            bool bPrime[MAX];
            void InitPrime()
            {
                int nMax = sqrt((double)MAX) + 1;
                bPrime[0] = bPrime[1] = true;
                for (int i = 2; i <= nMax; ++i)
                {
                    if (!bPrime[i])
                    {
                        for (int j = 2 * i; j < MAX; j += i)
                        {
                            bPrime[j] = true;
                        }
                    }
                }
            }
            LL multAndMod(LL a, LL b, LL n)
            {
                LL tmp = 0;
                while (b)
                {
                    if(b & 1)
                    {
                        tmp = (tmp + a) % n;
                    }
                    a = (a << 1) % n;
                    b >>= 1;
                }
                return tmp;
            }
            //計算a^u%n
            LL ModExp(LL a, LL u, LL n)
            {
                LL d = 1;
                a %= n;
                while (u)
                {
                    if (u & 1)
                    {
                        d = multAndMod(d, a, n);
                    }
                    a = multAndMod(a, a, n);
                    u >>= 1;
                }
                return d % n;
            }
            //判斷nN是不是合數(shù)
            bool Witness(LL a, LL nN)
            {
                LL u = nN - 1, t = 0;//將nN-1表示為u*2^t
                while (u % 2 == 0)
                {
                    t++;
                    u >>= 1;
                }
                LL x0 = ModExp(a, u, nN);//x是a^u
                LL x1;
                for (int i = 1; i <= t; ++i)
                {
                    x1 = multAndMod(x0, x0, nN);
                    if (x1 == 1 && x0 != nN - 1 && x0 != 1)
                    {
                        return true;
                    }
                    x0 = x1;
                }
                if (x1 != 1)
                {
                    return true;
                }
                return false;
            }
            //素數(shù)測試
            bool MillerRabin(LL nN)
            {
                //if (nN < MAX)return !bPrime[nN];
                const int TIME = 10;
                for (int i = 0; i < TIME; ++i)
                {
                    LL a = rand() % (nN - 1) + 1;
                    if (Witness(a, nN))
                    {
                        return false;
                    }
                }
                return true;
            }
            LL gcd(LL a, LL b)
            {
                if (a < b)swap(a, b);
                while (b)
                {
                    LL t = a;
                    a = b;
                    b = t % b;
                }
                return a;
            }
            //啟發(fā)式尋找nN的因子
            LL PollardRho(LL n, LL c)
            {
                LL i = 1, t = 2;
                LL x, y;
                LL ans;
                srand(time(NULL));  
                y = x = rand() % n;
                while(1)
                {
                    i++;
                    x = (multAndMod(x, x, n) + c) % n;
                    ans = gcd(y - x, n);
                    if(ans > 1 && ans < n)
                        return ans;
                    if(x == y)
                        return n;
                    if(t == i)
                    {
                        y = x;
                        t <<= 1;
                    }
                }
            }
            LL FindMin(LL nN, LL c)
            {
                //printf("nN:%I64u\n", nN);
                if (MillerRabin(nN) || nN <= 1)
                {
                    return nN;
                }
                LL p = nN;
                while (p >= nN) p = PollardRho(p, c--);
                if (p > 1)
                    p = FindMin(p, c);//分解p的最小因子
                if (p < nN)
                {
                    LL q = nN / p;
                    q = FindMin(q, c);//找到q的最小因子
                    p = min(p, q);
                }
                return p;
            }
            int main()
            {
                int nTest;
                srand(time(NULL));
                //InitPrime();
                scanf("%d", &nTest);
                while (nTest--)
                {
                    LL nN;
                    scanf("%I64u", &nN);
                    if (nN > 2 && nN % 2 == 0)
                    {
                        printf("2\n");
                    }
                    else if (nN == 2 || MillerRabin(nN))
                    {
                        printf("Prime\n");
                    }
                    else
                    {
                        printf("%I64u\n", FindMin(nN, 181));
                    }
                }
                return 0;
            }

            posted @ 2012-09-24 12:56 yx 閱讀(187) | 評論 (0)編輯 收藏

            僅列出標題
            共10頁: 1 2 3 4 5 6 7 8 9 Last 
            <2011年12月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567

            導航

            統(tǒng)計

            公告

            常用鏈接

            留言簿(3)

            隨筆分類

            隨筆檔案

            me

            好友

            同學

            網(wǎng)友

            搜索

            最新評論

            閱讀排行榜

            評論排行榜

            久久99久久无码毛片一区二区| 久久66热人妻偷产精品9| 日本加勒比久久精品| 精品久久久久久| 国产精品无码久久久久久| 97精品国产97久久久久久免费| 久久精品无码一区二区app| 合区精品久久久中文字幕一区| 久久精品成人欧美大片| 97r久久精品国产99国产精| 久久影院亚洲一区| 久久久av波多野一区二区| 天天久久狠狠色综合| 国产精品乱码久久久久久软件 | 久久精品女人天堂AV麻| 久久热这里只有精品在线观看| 漂亮人妻被黑人久久精品| 久久精品国产91久久麻豆自制| 一级女性全黄久久生活片免费 | 亚洲天堂久久精品| 狠狠综合久久AV一区二区三区| 97久久综合精品久久久综合| 色综合合久久天天给综看| 亚洲国产精品婷婷久久| 久久久久人妻一区二区三区vr| 久久婷婷人人澡人人| 国产福利电影一区二区三区,免费久久久久久久精| 亚洲&#228;v永久无码精品天堂久久 | 久久人人爽人人爽人人片AV麻烦| 久久精品一区二区国产| 久久精品国产久精国产果冻传媒| 久久精品这里只有精99品| 亚洲精品国产成人99久久| 99国产精品久久| 99久久精品费精品国产一区二区| 久久综合久久自在自线精品自| 人妻无码αv中文字幕久久琪琪布| 国产女人aaa级久久久级| 国产成人精品久久综合| 婷婷久久综合九色综合98| 国产精品久久久久影视不卡|