PAT A1093
這是活用遞推裡面比較經典的一種題型;
如果採用最簡單的暴力列舉,則會出現time limited錯誤。
這道題關鍵是能夠找到遞推的思路。對於序列中的每一個每一個A,如果能夠有PAT出現,則必定A的左右都有P和T;如果A左邊有a個P,右邊有b個T,則可以推出含有該A的PAT有a*b個;所以解法就被分解成以下幾個步驟:
1.尋找左邊P的個數;
2.尋找右邊T的個數;
3.遍歷A,進行左右的乘積;
至於P和T個數的儲存,我們可以仿照迪傑斯特拉演算法中的distance陣列來進行構造;
首先對於儲存P的陣列,進行輸入陣列的遍歷,每一次從前一位繼承P的數目,如果該位為P,則數目加一,從而構成一個儲存的P的陣列,其中index索引處的值代表輸入序列index位的左邊P的個數;
相關程式碼如下:
int len=strlen(str); for(int i=0;i<len;i++){ if(i>0){ leftNumP[i]=leftNumP[i-1]; } if(str[i]=='P'){ leftNumP[i]++; } }
對於T,則沒必要構建陣列,因為可以在計數的同時從後往前遍歷,這樣就將第三第四步結合在了一起;
相關程式碼如下;
nt ans=0,rightNumT=0; for(int i=len-1;i>=0;i--){ if(str[i]=='T'){ rightNumT++; }else if(str[i]=='A'){ ans=(ans+leftNumP[i]*rightNumT)%MOD; } }
從而可以通過一次遍歷完成後兩步的任務;
總體程式碼如下所示:
#include<cstdio> #include<stdlib.h> #include<cstring> const int MAXN=100010; const int MOD=1000000007; char str[MAXN]; int leftNumP[MAXN]={0}; int main(){ scanf("%s",str); int len=strlen(str); for(int i=0;i<len;i++){ if(i>0){ leftNumP[i]=leftNumP[i-1]; } if(str[i]=='P'){ leftNumP[i]++; } } int ans=0,rightNumT=0; for(int i=len-1;i>=0;i--){ if(str[i]=='T'){ rightNumT++; }else if(str[i]=='A'){ ans=(ans+leftNumP[i]*rightNumT)%MOD; } } printf("%d\n",ans); system("pause"); return 0; }