[科技]Loj#6564-最长公共子序列【bitset】
正題
題目鏈接:https://loj.ac/p/6564
題目大意
給兩個序列a,ba,ba,b求它們的最長公共子序列。
1≤n,m,ai,bi≤7×1041\leq n,m,a_i,b_i\leq 7\times 10^41≤n,m,ai?,bi?≤7×104
解題思路
無意間看到的一個bitsetbitsetbitset科技。
首先設fi,jf_{i,j}fi,j?表示aaa串匹配到第iii個bbb串匹配到第jjj個時的最長長度,做過dpdpdp套dpdpdp的應該知道fi,jf_{i,j}fi,j?的性質。
0≤fi,j?fi,j?1≤10\leq f_{i,j}-f_{i,j-1}\leq 10≤fi,j??fi,j?1?≤1
基本的思路就是設010101矩陣MMM滿足fi,j=∑k=1jMi,kf_{i,j}=\sum_{k=1}^jM_{i,k}fi,j?=∑k=1j?Mi,k?然后用bitsetbitsetbitset優化轉移
然后考慮一下怎么轉移,我們先預處理出ppp數組其中pip_ipi?表示數字iii出現的位置集合
我們的轉移要把MMM中的111盡量的往前移動并且看能否加上一個新的111。
假設現在的字符是ccc,那么我們將使用pcp_cpc?進行轉移。
我們把MMM中每個111作為結尾分成若干段(最后的000也是一段,順序是從低位到高位)。
那么對于一段中如果這一段pcp_cpc?有111那么我們就取最前面的那個111,這樣因為前面假設有jjj個111那么這次就匹配pcp_cpc?最前面的那個作為j+1j+1j+1。
但是我們顯然不可能一段一段做,我們可以考慮怎么把這個操作轉成位運算🤔。
考慮一下我們平時是怎么取一個010101串的第一位的,我們有lowbit(x)=((x?1)xorx)andxlowbit(x)=((x-1)\ xor\ x)\ and\ xlowbit(x)=((x?1)?xor?x)?and?x對吧。
發現這里每段分開取實際上難實現的地方只有x?1x-1x?1,考慮怎么實現這個問題。
因為111是段的末尾,所以每一段的開頭前面都是111,所以如果我們讓MMM左移一位那么就變成開頭是111了(需要注意補上第一段的111,所以應該是(M<<1)+1(M<<1)+1(M<<1)+1)
最后來說是
M=(X?(M<<1)+1)xorXandXM=(X-(M<<1)+1)\ xor\ X\ and\ XM=(X?(M<<1)+1)?xor?X?and?X
這樣我們就完成了MMM的轉移,因為需要位運算,所以需要手寫bitsetbitsetbitset。
時間復雜度O(nmω)O(\frac{nm}{\omega})O(ωnm?)
我是看這篇博客學的,看不懂的可以去看下:https://www.cnblogs.com/-Wallace-/p/bit-lcs.html
code
#include<cstdio> #include<cstring> #include<algorithm> #define ull unsigned long long using namespace std; const int N=7e4+10; int n,m,L; struct bitset{ull t[N/64+5];bitset(){memset(t,0,sizeof(t));return;}void set(int p){t[p>>6]|=(1ull<<(p&63));return;}void shift(){ull last=0;for(int i=0;i<L;i++){ull cur=t[i]>>63;(t[i]<<=1)|=last;last=cur;}return;}int count(){int ans=0;for(int i=0;i<L;i++){ull x=t[i];while(x)x-=(x&-x),ans++;}return ans;}bitset& operator=(const bitset &b){memcpy(t,b.t,sizeof(t));return *this;}bitset& operator|=(const bitset &b){for(int i=0;i<L;i++)t[i]|=b.t[i];return *this;}bitset& operator&=(const bitset &b){for(int i=0;i<L;i++)t[i]&=b.t[i];return *this;}bitset& operator^=(const bitset &b){for(int i=0;i<L;i++)t[i]^=b.t[i];return *this;} }p[N],f,g; bitset operator-(const bitset &a,const bitset &b){bitset tmp;ull last=0;for(int i=0;i<L;i++){ull cur=(a.t[i]<b.t[i]+last);tmp.t[i]=a.t[i]-b.t[i]-last;last=cur;}return tmp; } int main() {scanf("%d%d",&n,&m);L=(n>>6)+1;for(int i=1,c;i<=n;i++)scanf("%d",&c),p[c].set(i);for(int i=1,c;i<=m;i++){scanf("%d",&c);(g=f)|=p[c];f.shift();f.set(0);f=g-f;f^=g;f&=g;}printf("%d",f.count());return 0; }總結
以上是生活随笔為你收集整理的[科技]Loj#6564-最长公共子序列【bitset】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: lol怎么走a呢?
- 下一篇: 如何用路由器设置静态ip上网路由器怎么设