1. 程式人生 > 其它 >[Contest on 2022.5.6] 手寫 bitset 模板

[Contest on 2022.5.6] 手寫 bitset 模板

\(\cal T_1\)

\(\mathbb{D}\rm escription\)

\(\mathbb{S}\rm olution\)

$\mathbb{C}\rm ode $


\(\cal T_2\) 基因切割

\(\mathbb{D}\rm escription\)

\(\mathbf{namespace\_std}\) 乘坐戴夫的時光機器穿越回了現代,成為了⼀名醫學生。

這天,醫院新進了一些 \(\rm dna\) 切割機,這些機器可以識別輸入的 \(\rm dna\) 串中的某些子串,並將它們切割下來。

具體地,從右至左第 \(i\) 臺機器上有⼀個識別串,右端是輸入端,左端是輸出端。每當在輸入端投入⼀個鹼基的時候,機器中的所有鹼基會向左移動⼀格,若機器已滿,最左側的鹼基會從機器的輸出端彈出,進入左側機器的輸入端,或者完成處理後的結果池。

特別地,若⼀個機器內的鹼基序列恰好為它的識別串,這臺機器會立即把這段序列保留下來,並將自身清空。

他有⼀個 \(\rm dna\) 串,他將這個串放入了機器。由於整段放入機器後機器內可能會有殘留的內容,所以他會在放入之後從右到左依次將每臺機器殘餘的內容投入左側的機器,並將最左側機器的輸出投入結果池。由於 \(\rm dna\) 切割機的運⾏速度很慢,他想讓你寫⼀個程式模擬切割的結果,即最終輸出到結果池的 \(\rm dna\) 串。

\(|S|,m,\sum|T_i|\le 10^5\).

\(\mathbb{S}\rm olution\)

對於字串 \(S\) 包含且僅包含字元 AT,特徵串均為 AT

,且將 AT 分別視為左右括號字串 \(S\) 為合法括號序列的情況:此時可以建出括號樹,那麼一個節點的子樹深度就代表自己在第幾臺機器上被剪下,所以刪除所有子樹深度小於等於 \(m\) 的點再進行還原就是答案。

這題可以用 \(\rm bitset\) 來做:考慮對每種字元開一個 \(\rm bitset\),那麼判斷識別串的方法就是右移 \(i\) 位再取並。用 \(\text{find_next()}\) 函式找到所有的 \(1\) 的位置(識別串的開頭),再依次刪除即可。

原理很簡單,但是我真的寫了很久。

$\mathbb{C}\rm ode $

# pragma GCC optimize("Ofast")
# include <cstdio>
# include <cctype>
# define print(x,y) write(x), putchar(y)

template <class T>
inline T read(const T sample) {
    T x=0; char s; bool f=0;
    while(!isdigit(s=getchar())) f|=(s=='-');
    for(; isdigit(s); s=getchar()) x=(x<<1)+(x<<3)+(s^48);
    return f? -x: x;
}
template <class T>
inline void write(T x) {
    static int writ[50], w_tp=0;
    if(x<0) putchar('-'), x=-x;
    do writ[++w_tp] = x-x/10*10, x/=10; while(x);
    while(putchar(writ[w_tp--]^48), w_tp);
}

# include <cstring>
using namespace std;

const int maxn = 1e5+5;

int n,m;
char str[maxn];

struct my_bitset {
    typedef unsigned int u32;
    typedef unsigned long long u64;
    const static u32 BLOCK = 64;
    const static u32 SIZE = maxn/BLOCK+((maxn%BLOCK)>0);
    u64 v[SIZE];
    inline void reset() { memset(v,0,sizeof(u64)*SIZE); }
    inline bool test(const u32& x) const {
        return v[x>>6]>>(x&63)&1;
    }
    inline void set(const u32& x) { v[x>>6] |= 1ull<<(x&63); }
    inline u32 _find_after_block(const u32& x) const {
        for(u32 i=x;i<SIZE;++i) if(v[i])
            return u32(__builtin_ctzll(v[i]))^(i<<6);
        return maxn;
    }
    inline u32 _find_next(const u32& x) const {
        u64 cur = v[x>>6]>>(x&63)>>1; if(cur) 
            return u32(__builtin_ctzll(cur))+x+1;
        return _find_after_block((x>>6)+1);
    }
    inline u32 _find_first() const {
        return _find_after_block(0);
    }
    inline void operator &= (const my_bitset& rhs) {
        for(u32 i=0;i<SIZE;++i) v[i] &= rhs.v[i];
    }
    inline void operator |= (const my_bitset& rhs) {
        for(u32 i=0;i<SIZE;++i) v[i] |= rhs.v[i];
    }
    inline void operator ^= (const my_bitset& rhs) {
        for(u32 i=0;i<SIZE;++i) v[i] ^= rhs.v[i];
    }
    inline void operator <<= (const u32& x) {
        u32 y = x>>6, z = x&63;
        if(z) for(u32 i=SIZE-1;i>y;--i)
            v[i] = (v[i-y]<<z)|(v[i-y-1]>>(BLOCK-z));
        else for(u32 i=SIZE-1;i>y;--i)
            v[i] = v[i-y];
        v[y] = v[0]<<z;
        for(u32 i=0;i<y;++i) v[i]=0;
    }
    inline void operator >>= (const u32& x) {
        u32 y = x>>6, z = x&63;
        if(z) for(u32 i=0;i<SIZE-y-1;++i)
            v[i] = (v[i+y]>>z)|(v[i+y+1]<<(BLOCK-z));
        else for(u32 i=0;i<SIZE-y-1;++i)
            v[i] = v[i+y];
        v[SIZE-y-1] = v[SIZE-1]>>z;
        for(u32 i=SIZE-y;i<SIZE;++i) v[i]=0;
    }
    inline my_bitset& operator = (const my_bitset& rhs) {
		memcpy(v,rhs.v,sizeof(u64)*SIZE);
        return *this;
	}
} ty[4],all,cur,now,omg;

inline int mp(const char& ch) {
    if(ch=='A') return 0;
    if(ch=='G') return 1;
    if(ch=='C') return 2;
    return 3;
}
inline char reMp(int i) {
    if(i==0) return 'A';
    if(i==1) return 'G';
    if(i==2) return 'C';
    return 'T';
}

int main() {
    freopen("dna.in","r",stdin);
    freopen("dna.out","w",stdout);
    scanf("%s",str); n = strlen(str); const int N=n;
    for(int i=0;i<n;++i) ty[mp(str[i])].set(i), all.set(i);
    for(int m=read(9); m; --m) {
        scanf("%s",str); int len = strlen(str), bas=0;
        cur = ty[mp(str[0])]; 
        for(int i=1;i<len;++i) {
            now = ty[mp(str[i])], now>>=i;
            cur &= now;
        } 
        for(int i=cur._find_first(); i^maxn; i=cur._find_next(i+len-1)) {
            now = all; now >>= (N-i+bas);
            for(int j=0;j<4;++j) {
                omg=ty[j], omg>>=i+len-bas, omg<<=i-bas;
                ty[j] &= now, ty[j] |= omg;
            }
            n -= len, bas += len;
        }
    }
    for(int i=0;i<n;++i)
        for(int j=0;j<4;++j)
            if(ty[j].test(i)) putchar(reMp(j));
    return 0;
}

\(\cal T_3\)

\(\mathbb{D}\rm escription\)

\(\mathbb{S}\rm olution\)

$\mathbb{C}\rm ode $