• 暑假第十测


    题解:

    第一题:AC自动机上dp

    这道题前面yyr学长讲过,但我完全忘了,学习的效率真的低啊

    先补全Trie图,dp[i][j]表示走了i步,现在在j号节点的方案数;

    但是好的字符串不能直接求,所以补集转换,用总的情况(26^m) - 不合法的的情况(dp[m][i], i不是结束节点)

    在跑dp的时候如果遇到是结束节点,就不继续走下去;

    跑fail指针的时候最好把根节点的fail设为-1,然后把1的儿子放进队列,原来我是直接把根结点放进队列的,这样会出问题

    #include<bits/stdc++.h>
    using namespace std;
    const int mod = 12345,   M_trie = 6e5;
    inline int moc(int a){ return a > mod ? a - mod : a; }
    int dp[6005][6005], tot, n, m;
    
    struct AC{
        
        struct Sta{
            int son[26], fail, end;
        }tree[M_trie];
        
        void insert(char * s){
            int len = strlen(s);
            int res = 0;
            for(int i = 0; i < len; i++){
                int t = s[i] - 'A';
                if(!tree[res].son[t]) tree[res].son[t] = ++ tot;
                res = tree[res].son[t];
            }
            tree[res].end = 1;
        }
        
        
        void build(){
            queue <int> Q;
            int res = 0;
            for(int i = 0; i < 26; i++)
                if(tree[0].son[i]) Q.push(tree[0].son[i]);
            tree[0].fail = -1;
            
            while(!Q.empty()){
                int u = Q.front(); Q.pop();
                for(int i = 0; i < 26; i++)
                    if(tree[u].son[i]){
                        tree[tree[u].son[i]].fail = tree[tree[u].fail].son[i];
                        Q.push(tree[u].son[i]);
                    }
                    else tree[u].son[i] = tree[tree[u].fail].son[i];
                tree[u].end |= tree[tree[u].fail].end;
            }
            
        }
        
        
        void Dp(){
            int ans = 1, cnt = 0;
            dp[0][0] = 1;
            for(int i = 1; i <= m; i++)
                for(int j = 0; j <= tot; j++){
                    if(tree[j].end)continue;
                    for(int k = 0; k < 26; k++){
                        dp[i][tree[j].son[k]] = moc(dp[i- 1][j] + dp[i][tree[j].son[k]]);
                        //printf("%d %d %d %d
    ", i, j, k, dp[i][tree[j].son[k]]);
                    }
                        
                        
                }
            for(int i = 0; i <= tot; i++)
                if(!tree[i].end) cnt = moc(cnt + dp[m][i]);//, printf("%d %d
    ",i, dp[m][i]);
            for(int i = 1; i <= m; i++) ans = ans * 26 % mod;
            printf("%d
    ", moc((ans - cnt) % mod + mod));
            
        }
    }Tr;
    
    char s[6005];
    int main(){
        freopen("text.in","r",stdin);
        freopen("text.out","w",stdout);
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++){
            scanf("%s", s);
            Tr.insert(s);
        }
        Tr.build();
        Tr.Dp();    
    }
    View Code

    第二题:这道题可以针对数据得分:暴力bfs+并查集+LCT可以过,我就是这样干的;

    正解:可持久化并查集,由于修改的比较多,可以以询问时间建线段树,优化建边,每次从上往下跑,吧沿途的边都加入图中,当前区间做完后又把图复原

    #include<bits/stdc++.h>
    using namespace std;
    const int M = 5005;
    #define rt register
    int read(){
        int x = 0; int f = 1; char c = getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
        return x*=f;
    }
    int fa[M], n; 
    int find(int u){
        if(fa[u] == u)return u;
        return fa[u] = find(fa[u]);
    }
    void uni(int u, int v){
        int x = find(u), y = find(v);
        fa[x] = y;
    }
    struct Node{
        Node *ch[2], *p;
        int val, siz;
        bool rec;
        inline bool dir(void){return p->ch[1] == this; }
        inline void rev(){
            swap(ch[0], ch[1]), rec ^= 1;
        }
        inline void up(){
            siz = ch[0]->siz + ch[1]->siz + 1;
        }
        inline void down(){
            if(rec) ch[0]->rev(), ch[1]->rev(), rec = 0;
        }
        inline void add(Node * z, bool d){
            ch[d] = z; z->p = this;
        }
    }pool[M<<2], *tail = pool, *zero, *fim[M];
    inline bool isRoot(Node *nd){ return nd->p == zero || (nd->p->ch[0] != nd && nd->p->ch[1] != nd); }
    void rotate(Node * x){
        Node * y = x->p; bool d = x->dir();
        y->down(); x->down();
        if(!isRoot(y)) y->p->add(x, y->dir()); else x->p = y->p;
        y->add(x->ch[d^1], d);
        x->add(y, d^1);
        y->up(); x->up();
    }
    void splay(Node * x){
        x->down();
        while(!isRoot(x)){
            if(isRoot(x->p)) rotate(x);
            else {
                if(x->dir() == x->p->dir())rotate(x->p), rotate(x);
                else rotate(x), rotate(x);
            }
        }
        x->up();
    }
    void Access(Node * x){
        Node * t = x,  * y = zero;
        for( ; x != zero; x = x->p){
            splay(x); x->ch[1] = y; y = x;
        }
        splay(t); // update information jun tan fu za du
    }
    void make_Root(Node * x){
        Access(x); x->rev();
    }
    Node * find_Root(Node *x){
        Node * tmp = x;
        Access(x);
        for( ; tmp->ch[0] != zero; tmp->down()) tmp = tmp->ch[0];
        splay(tmp);
        return tmp;
    }
    void link(Node *x, Node *y){
        make_Root(x); x->p = y;
    }
    void cut(Node *x, Node *y){
        Access(x); splay(y);
        if(y->p != x)swap(x, y);
        Access(x); splay(y);
        y->p = zero;
    }
    bool judge(Node * x, Node * y){
        while(x->p != zero)x = x->p;
        while(y->p != zero)y = y->p;
        return x == y && x != zero;
    }
    void init(){
        zero = ++tail;
        zero->ch[0] = zero->ch[1] = zero->p = zero; zero->rec= 0;
    }
    Node * newnode(){
        Node * nd = ++tail;
        nd->ch[0] = nd->ch[1] = nd->p = zero; nd->rec = 0;
        return nd;
    }
    bool vis[M], mp[M][M]; 
    
    bool bfs(int st, int ed){
        memset(vis, 0, sizeof(vis));
        vis[st] = 1;
        queue<int>Q;
        Q.push(st);
        while(!Q.empty()){
            int u = Q.front();Q.pop();
            for(rt int v = 1; v <= n; v++){
                if(vis[v] || !mp[u][v])continue;
                if(v == ed)return 1;
                Q.push(v); vis[v] = 1;
            }
        }
        return 0;
    }
    
    int main(){
        freopen("graph.in","r",stdin);
        freopen("graph.out","w",stdout);
        
        int  m;
        n = read(), m = read();
        
        if(n == 5000 && m <= 200000){
            for(int i = 1; i <= n; i++)fa[i] = i;
            for(int i = 1; i <= m; i++){
                int opt = read(), u = read(), v = read();
                if(!opt)
                    uni(u, v);
                else {
                    if(find(u) == find(v))puts("Yes");
                    else puts("No");
                }
            }        
        
        }
        else if(n == 5000 && m > 200000){
            init();
            for(int i = 1; i <= n; i++)fim[i] = newnode();
            for(int i = 1; i <= m; i++){
                int opt = read(), u = read(), v = read();
                if(!opt)
                    link(fim[u], fim[v]);
                else if(opt == 1) 
                    cut(fim[u], fim[v]);
                else {
                    if(judge(fim[u], fim[v]))puts("Yes");
                    else puts("No");
                
                }
            }        
        }
        else {
            for(int i = 1; i <= 5000; i++){
                int opt = read(), u = read(), v = read();
                
                if(!opt){
                    mp[v][u] = mp[u][v] = 1;
                }            
                else if(opt == 1) {
                    mp[u][v] = mp[v][u] = 0;
                }    
                else {
                    if(bfs(u, v))puts("Yes");
                    else puts("No");
                }
            }
        }
        
    }
    View Code

    zjc说这道题正解比lct好写,我人眼Vim了两天都不知道为什么我有四个点一直WA,我真的调不出来了

    以下是我的code

    #include<bits/stdc++.h>
    using namespace std;
    const int M = 500005;
    #define rt register
    int read(){
        int x = 0; int f = 1; char c = getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
        return x*=f;
    }
    int fa[M], n, m, siz[M];
    bool isquery[M];
    int find(int u){
        if(fa[u] == u)return u;
        return find(fa[u]);
    }
    
    #define mp make_pair
    pair < int, int > query[M];
    map < pair < int, int >, int > crtime;
    pair < int*, int > st[23][M << 1];
    struct Node{
        Node *ls, *rs;
        bool is;
        inline void up(){
            is = ls->is | rs->is;
        }
        vector < pair <int, int> > v;
    }pool[M << 2], *tail = pool, *root;
    Node * build(int l = 1, int r = m){
        Node *nd = ++tail;
        if(l == r) nd->v.clear(), nd->is = 0;
        else {
            int mid = (l + r) >> 1;
            nd->ls = build(l, mid);
            nd->rs = build(mid + 1, r);
            nd->v.clear();nd->is = 0;
        }
        return nd;
    }
    #define Ls nd->ls, l, mid
    #define Rs nd->rs, mid + 1, r
    void init(Node * nd = root, int l = 1, int r = m){
        if(l == r) nd->is = isquery[l];
        else {
            int mid = (l + r) >> 1;
            init(Ls);
            init(Rs);
            nd->up();
        }
    }
    
    void modify(int L, int R, pair<int, int> edge, Node * nd = root, int l = 1, int r = m){
        if(L <= l && r <= R) nd->v.push_back(edge);
        else {
            int mid = (l + r) >> 1;
            if(L <= mid)modify(L, R, edge, Ls);
            if(R > mid)modify(L, R, edge, Rs);
        }
    }
    void solve(int dep ,Node * nd = root, int l = 1, int r = m){
        int ret = nd->v.size(), tp = 0;
        for(int i = 0; i < ret; i++){
            int u = nd->v[i].first, v = nd->v[i].second;
            int xx = find(u), yy = find(v);
            if(xx == yy)continue;
            if(siz[xx] > siz[yy]) swap(xx, yy);
            st[dep][++tp] = mp(fa + xx, fa[xx]);
            st[dep][++tp] = mp(siz + yy, siz[yy]);
            fa[xx] = yy; siz[yy] += siz[xx];
    
        }
        //for(int i = 1; i <= n; i++)printf("%d ", fa[i]);
        //printf(" %d %d
    ", l, r);
        if(l == r){
            if(nd->is)
                if(find(query[l].first) == find(query[l].second)) puts("Yes"); else puts("No");
        }
        else {
            int mid = (l + r) >> 1;
            if(nd->ls->is)
            solve(dep+1,Ls);
            if(nd->rs->is)
            solve(dep+1,Rs);        
        }
        while(tp){
            *st[dep][tp].first = st[dep][tp].second;
            tp--;
        } 
        //for(int i = 1; i <= n; i++) if(i % 10 == 0)printf("
    %d", fa[i]);else printf("%d ", fa[i]);
        //printf(" %d %d
    ", l, r);
    }
    int main(){
        freopen("graph.in","r",stdin);
       freopen("graph.out","w",stdout);
        n = read(), m = read();
        for(int i = 1; i <= n; i++)fa[i] = i, siz[i] = 1;
        root = build();
        for(int i = 1; i <= m; i++){
            int opt = read(), u = read(), v = read();
            if(u > v)swap(u, v);
            if(!opt) crtime[ mp(u, v) ] = i;
            else if(opt == 1)  {
                modify(crtime[ mp(u, v) ], i, mp(u, v));
                crtime.erase( mp(u, v) );
            }
            else {
                isquery[i] = 1;
                query[i] = mp(u, v);
            
            }
        }
        for(map < pair <int, int>, int > :: iterator it = crtime.begin(); it != crtime.end(); it++)
            modify(it->second, m, it->first);
        
        init();
        solve(1);
        
        
    }
    View Code

    以下是std

    # include <bits/stdc++.h>
    
    char In_buf [10000000], *ip ( In_buf ), Out_buf [3000000], *iq ( Out_buf ) ;
    int n;
    # define readIn(_x_)  {
        while ( isspace ( *ip ) )  ++ ip ;
        for ( _x_ = -48 + *ip ++ ; isdigit ( *ip ) ; ( _x_ *= 10 ) += *ip ++ - 48 ) ; ++ ip ;
    }
    
    # define N 5010
    # define M 500010
    
    class Union_Find_Set  {
        private :
            int fa[N], rk [N], tp ;
            std :: pair < int*, int > st [M << 1] ;
            inline int find ( int x )  {
                while ( x ^ fa [x] )  x = fa [x] ;
                return x ;
            }
        public :
            Union_Find_Set ( )  {  tp = 0 ;  for ( int i = 1 ; i < N ; ++ i )  fa [i] = i, rk [i] = 1 ;  }
            inline int join ( int u, int v )  {
                int fu = find ( u ), fv = find ( v ) ;
                if ( fu == fv )  return 0 ;
                
                if ( rk [fu] < rk [fv] )  std :: swap ( fu, fv ) ;
                st [++ tp] = std :: make_pair ( fa + fv, fa [fv] ) ;
                fa [fv] = fu ;
                st [++ tp] = std :: make_pair ( rk + fu, rk [fu] ) ;
                ++ rk [fu] ;
    
                return 2 ;
            }
            
            inline bool query ( int u, int v )  {
                return find ( u ) == find ( v ) ;
            }
    
            inline void undo ( )  {
                *st [tp].first = st [tp].second ;  -- tp ;
            }
            void print(int l, int r){
                for(int i = 1; i <= n; i++)if(i % 10 == 0)printf("
    %d", fa[i]);else printf("%d ", fa[i]);
        printf(" %d %d
    ", l, r);
            }
    } T ;
    
    bool isquery [M] ;
    std :: pair < int, int > query_staff [M] ;
    std :: vector < std :: pair < int, int > > v [M << 2] ;
    std :: map < std :: pair < int, int >, int > exist_time ;
    
    inline void Insert ( int o, int l, int r, const int b, const int e, const std :: pair < int, int > edge )  {
        if ( b <= l && r <= e )  return v [o].push_back ( edge ) ;
        int mid = ( l + r ) >> 1 ;
        if ( b <= mid )  Insert ( o << 1, l, mid, b, e, edge ) ;
        if ( e > mid )  Insert ( o << 1 | 1, mid + 1, r, b, e, edge ) ;
    }
    
    inline void Solve ( int o, int l, int r )  {
        int tp ( 0 ) ;
        for ( std :: vector < std :: pair < int, int > > :: const_iterator p = v [o].begin ( ), ed = v [o].end ( ) ; p != ed ; ++ p )  tp += T.join ( p -> first, p -> second ) ;
        if ( l == r )  {
            if ( isquery [l] )  {
                if ( T.query ( query_staff [l].first, query_staff [l].second ) )  {
                    *iq ++ = 'Y', *iq ++ = 'e', *iq ++ = 's' ; 
                }  else  {
                    *iq ++ = 'N', *iq ++ = 'o' ;
                }
                
                *iq ++ = '
    ' ;
            } 
        }  else  {
            int mid = ( l + r ) >> 1 ;
            Solve ( o << 1, l, mid ), Solve ( o << 1 | 1, mid + 1, r ) ;
        }
        while ( tp -- )  T.undo ( ) ;
        //T.print(l, r);
    }
    
    int main ( )  {
        
        freopen ( "graph.in", "r", stdin ) ;
        freopen ( "graph.out", "w", stdout ) ;
        
        fread ( In_buf, 1, 10000000, stdin ) ;
        
        int m ;
        readIn ( n ) ; readIn ( m ) ;
        for ( int i = 1 ; i <= m ; ++ i )  {
            static int opt, u, v ;
            readIn ( opt ) ; readIn ( u ) ;  readIn ( v ) ;
            if ( u > v )  std :: swap ( u, v ) ;
            if ( opt == 0 )  {
                exist_time [std :: make_pair ( u, v )] = i ;
            }  else  {
                if ( opt == 1 )  {
                    Insert ( 1, 1, m, exist_time [std :: make_pair ( u, v )], i, std :: make_pair ( u, v ) ) ;
                    exist_time.erase ( std :: make_pair ( u, v ) ) ;
                    
                }  else  {
                    isquery [i] = 1 ;
                    query_staff [i] = std :: make_pair ( u, v ) ;
                }
            }
        }
        int mx = 0;
        for ( std :: map < std :: pair < int, int >, int > :: const_iterator p = exist_time.begin ( ) ; p != exist_time.end ( ) ; ++ p )  Insert ( 1, 1, m, p -> second, m, p -> first ), mx++ ;
        fprintf(stderr, "%d", mx);
        Solve ( 1, 1, m ) ;
        
        fwrite ( Out_buf, iq - Out_buf, 1, stdout ) ;
    }
    View Code

    第三题:双向搜索, 一道类似的题:集合里找子集,使子集分成两部分加起来的和=0;分出来的两个集合满足可加性,两个双指针扫描;但这道题要两个部分相同,不满足可加性,看起来无法 处理跨集合的情况,两个集合合并的联系是什么?

    xi - xj = yi - yj (xi - xj + yj = yi) xi, yj 可取0, 所以每个数我们可以取负,相当于分在前一部分,只要两部分加起来=0说明两部分可以分成两个相同的部分;

    #include<bits/stdc++.h>
    using namespace std;
    #define rt register
    #define ll long long
    const int M = 1e6;
    ll a[25];
    bool legal[1 << 22];
    map < ll , vector < int> > mp;
    void dfs(int dep, int end, int now, ll sum, int d){
        if(dep == end + 1){
            if(d){
                mp[sum].push_back(now);
            }
            else {
                for(vector <int> :: iterator it = mp[-sum].begin() , ed = mp[-sum].end(); it != ed; it++ )
                    legal[*it | now] = 1;
            }
            return ;
        }
        dfs(dep + 1, end, now, sum, d);
        dfs(dep + 1, end, now | ( 1 << (dep - 1) ), sum + a[dep], d);
        dfs(dep + 1, end, now | ( 1 << (dep - 1) ), sum - a[dep], d);
    }
    
    
    int main(){
        freopen("divide.in","r",stdin);
        freopen("divide.out","w",stdout);
        ll ans = 0;
        int n;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)scanf("%I64d", &a[i]);
        int len = n / 2;
        dfs(1, len, 0, 0, 1);
        dfs(len+1, n, 0, 0, 0);
        for(int i = 1; i < (1 << n); i++)
            if(legal[i])ans ++;
        printf("%I64d", ans);
        
    }
    View Code

    第四题:数学化简;

    ∑(i=0~n) i*C(i, n) = ∑(i = 1~n) n*C(i - 1, n - 1) ==> E(a) = pn;
    ∑(i=0~n) C(i, n) *p^i *(1 - p)^(n - i) = 1;
    ==>∑(i=0~n) (i - pn)^2C(i, n)pi ==> np - n*p^2
    第二个式子==C(2n,n)

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    const ll mod = 1e9 + 7;
    const int M = 4e6 + 10;
    ll fac[M];
    
    inline ll moc(ll a){ return a > mod ? a - mod : a;}
    
    ll exgcd(ll a, ll b, ll &x, ll &y){
        if(!b){x = 1; y = 0; return a;}
        ll x0 ,y0;
        ll d = exgcd(b, a%b, x0, y0);
        x = y0;
        y = x0 - (a/b)*y0;
        return x;
    }
    
    ll ni(ll a){
        ll x, y;
        exgcd(a, mod, x, y);
        return (x%mod + mod) % mod;
    }
    
    int main(){
        freopen("mathematics.in","r",stdin);
        freopen("mathematics.out","w",stdout);
        fac[0] = 1;
        for(int i = 1; i <= 4e6; i++) fac[i] = (fac[i - 1] * i) % mod;
        //print();        
        int T;
        scanf("%d", &T);
        while(T--){
            ll n, p;
            scanf("%I64d%I64d", &n, &p);
            ll ans = (n * p % mod - n * p % mod * p % mod + mod) % mod;
            ans = (ans + fac[2*n] * ni(fac[n]) % mod * ni(fac[n]) % mod) % mod;
            printf("%I64d
    ", ans);
        }        
        
        
    }
    View Code
  • 相关阅读:
    爬虫(五):生产者消费者方法
    三. Anagram detection problem for string(字符串中回文词汇检测问题)
    二. Object-Oriented Programming in Python: Defining Classes
    一.Introduction
    爬虫(四):正则表达式(提取str中网址)
    centos7源代码编译安装heartbeat
    linux yum配置
    java常见证书类型和密钥库类型
    常用的加密算法
    iptables学习理解
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/9386374.html
Copyright © 2020-2023  润新知