2020年HDU多校第二場 1012 String Distance(序列自動機,dp)
阿新 • • 發佈:2020-07-24
2020年HDU多校第二場 1012 String Distance(序列自動機,dp)
題意:給兩個字串,第一個很長,第二個很短,q次詢問每次給一個l,r問操作多少次使第一串的l到r與第二串相等,每次操作選擇兩串其1在任意位置增加元素或刪除元素;
題解:首先很容易想到增加操作是沒有必要的,因為我可以在某字串增加必然可以在另一串相同位置刪除,所以很明顯就是求兩串的最長公共子序列,普通的最長公共子序列是寫不了的,因為他給的l的限制,我想預處理出所有dp的話,時間與空間都不夠,我們發現,第二個字串的長度特別短,所以可以用序列自動機對第一個字串進行降維打擊,然後每次詢問進行一次dp既可,O(20*20)。dp的話用記憶化搜尋會好寫很多,可惜HDU卡的太死了,搜尋寫法超時,這裡給上遞推式的寫法。
#include<iostream> #include<cstring> using namespace std; const int maxn=1e9+7; int m,len,t,n,q,g[100007][30],dp[27][27],l,r; char s1[100007],s2[100007]; int solve(){ for(int i=0;i<=m;i++){ for(int j=0;j<=m;j++){ dp[i][j]=100006; } } for(int i=0;i<=m;i++)dp[i][0]=l; int ans=0; for(int i=1;i<=m;i++){ for(int j=1;j<=i;j++){ dp[i][j]=dp[i-1][j]; dp[i][j]=min(dp[i][j],g[dp[i-1][j-1]][s2[i]-'a']+1); } } for(int i=1;i<=m;i++){ for(int j=1;j<=i;j++){ if(dp[i][j]<=r+1){ ans=max(ans,j); } } } return ans; } void init(){ memset(g,maxn,sizeof(g)); } int main(){ scanf("%d",&t); while(t--){ init(); scanf("%s%s",s1+1,s2+1); len=strlen(s1+1); m=strlen(s2+1); for(int i=0;i<=25;i++)g[len+1][i]=1e9; for(int i=len;i>=1;i--){ for(int j=0;j<=25;j++){ g[i][j]=g[i+1][j]; } g[i][s1[i]-'a']=i; } scanf("%d",&q); while(q--){ scanf("%d%d",&l,&r); printf("%d\n",m+r-l+1-2*solve()); } } }