zoukankan      html  css  js  c++  java
  • 2019牛客多校第四场题解

    2019牛客多校第四场题解

    题目链接

    A.meeting

    设最远关键点距离为(d),那么答案就是(lceilfrac{d}{2} ceil)
    直接换根胡乱dp也行。。

    Code
    #include <bits/stdc++.h>
    using namespace std;
     
    const int maxn = 1e5+10;
    vector<int>g[maxn];
    int vis[maxn];
    int len,st,ed;
    void dfs(int u,int fa,int dep){
        if(vis[u]){
            if(dep>len){
                len=dep;
                ed=u;
            }
        }
        for(int i=0;i<g[u].size();i++){
            int v=g[u][i];
            if(v==fa)continue;
            dfs(v,u,dep+1);
        }
    }
    int main(){
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n,k;
        cin>>n>>k;
        for(int i=1;i<n;i++){
            int u,v;
            cin>>u>>v;
            g[u].push_back(v),g[v].push_back(u);
        }
        for(int i=1;i<=k;i++){
            cin>>st;
            vis[st]=1;
        }
        len=1,ed=st;
        dfs(st,0,1);
        st=ed;
        dfs(st,0,1);
        cout<<len/2<<endl;
    }
    

    B.xor

    据说是个线性基交的板子题,但还是有一大波神仙A了。。
    求交的话大概就是对于两个基集合(B1,B2),枚举(B2)中的基,如果与(B1)线性无关,那么就插在(B1)里面去;否则就对于当前的基,异或掉(B1)中之前插进去的(B2)的基,然后将其插入交集里面就行了。证明的话可以看看博客:传送门

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned int ui;
    const int N = 50005;
    int n, m;
    struct node{
        ui r[32], f[32];
        bool ins(ui x) {
            for(int i = 31; i >= 0; i--) {
                if(x >> i) {
                    if(!r[i]) {r[i] = x; return 1;}
                    else x ^= r[i];
                }
            }
            return 0;
        }
        bool ins2(ui x) {
            ui tmp = x;
            for(int i = 31; i >= 0; i--) {
                if(x >> i) {
                    if(!r[i]) {r[i] = x; f[i] = tmp; return 1;}
                    else {
                        x ^= r[i]; tmp ^= f[i];
                    }
                }
            }
            return 0;
        }
        void clear() {
            for(int i = 0; i <= 31; i++) r[i] = f[i] = 0;
        }
        bool find(ui x) {
            for(int i = 31; i >= 0; i--) {
                if(x >> i) {
                    if(!r[i]) return 0;
                    x ^= r[i];
                }
            }
            return x == 0;
        }
        int calc(ui x) {
            int ans = 0;
            for(int i = 31; i >= 0; i--) {
                if(x >> i) {
                    x ^= r[i];
                    ans ^= f[i];
                }
            }
            return ans;
        }
    };
    node _merge(node u, node v) {
        node tmp, res; res.clear();
        tmp = u;
        for(int i = 31; i >= 0; i--) {
            ui x = v.r[i];
            if(tmp.find(x)) {
                res.ins(x ^ tmp.calc(x));
            } else tmp.ins2(x);
        }
        return res;
    }
    ui a[N][33];
    node b[N << 2];
    void build(int o, int l, int r) {
        if(l == r) {
            b[o].clear();
            for(int j = 1; j <= 32; j++) b[o].ins(a[l][j]);
            return ;
        }
        int mid = (l + r) >> 1;
        build(o << 1, l, mid); build(o << 1|1, mid + 1, r);
        b[o] = _merge(b[o << 1], b[o << 1|1]);
    }
    bool query(int o, int l, int r, int L, int R, ui v) {
        if(L <= l && r <= R) {
            return b[o].find(v);
        }
        int mid = (l + r) >> 1;
        bool ans = 1;
        if(L <= mid) ans &= query(o << 1, l, mid, L, R, v);
        if(R > mid) ans &= query(o << 1|1, mid + 1, r, L, R, v) ;
        return ans;
    }
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> n >> m;
        for(int i = 1; i <= n; i++) {
            int k; cin >> k;
            for(int j = 1; j <= k; j++) cin >> a[i][j];
        }
        build(1, 1, n);
        for(int i = 1, l, r; i <= m; i++) {
            ui x; cin >> l >> r >> x;
            if(query(1, 1, n, l, r, x)) cout << "YES" << '
    ';
            else cout << "NO" << '
    ';
        }
        return 0;
    }
    
    

    C.sequence

    南昌网络赛出过,单调栈+线段树维护就行。

    Code
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef double db;
    typedef long double ld;
    const int MAXN = 3e6 + 5, MAXM = 2e4 + 5, BOUND = 2e5 + 5, MOD = 1e9 + 7, INF = 0x3f3f3f3f, base = 10000;
    const ll INFL = 0x3f3f3f3f3f3f3f3f;
    const double PI = acos(-1.0), eps = 1e-9;
    #define mid l + ((r-l)>>1)
    #define lson o<<1,l,m
    #define rson o<<1|1,m+1,r
    #define lc(x) ch[x][0]
    #define pii pair<int,int>
    #define vi vector<int>
    #define RR register int
    #define rc(x) ch[x][1]
    #define rep(i,a,b) for(RR i=(a);i<=(b);++i)
    #define random(a,b) ((a)+rand()%((b)-(a)+1))
    struct Istream {
        template <class T>
        Istream &operator >>(T &x) {
            static char ch; static bool neg;
            for (ch = neg = 0; ch < '0' || '9' < ch; neg |= ch == '-', ch = getchar());
            for (x = 0; '0' <= ch && ch <= '9'; (x *= 10) += ch - '0', ch = getchar());
            x = neg ? -x : x;
            return *this;
        }
    }fin;
     
    struct Ostream {
        template <class T>
        Ostream &operator <<(T x) {
            x < 0 && (putchar('-'), x = -x);
            static char stack[233]; static int top;
            for (top = 0; x; stack[++top] = x % 10 + '0', x /= 10);
            for (top == 0 && (stack[top = 1] = '0'); top; putchar(stack[top--]));
            return *this;
        }
     
        Ostream &operator <<(char ch) {
            putchar(ch);
            return *this;
        }
    }fout;
    int n, a[MAXN], b[MAXN], l1[MAXN], r1[MAXN], st[MAXN], top = 0;
    ll maxv[MAXN << 2][2], minv[MAXN << 2][2], s[MAXN], s2[MAXN];
    inline void pushUp(int o) {
        rep(i, 0, 1) {
            maxv[o][i] = max(maxv[o << 1][i], maxv[o << 1 | 1][i]);
            minv[o][i] = min(minv[o << 1][i], minv[o << 1 | 1][i]);
        }
    }
    void build(int o, int l, int r) {
        if (l == r) {
            maxv[o][0] = minv[o][0] = s[l];
            maxv[o][1] = minv[o][1] = s2[l];
            return;
        }
        int m = mid;
        build(lson); build(rson);
        pushUp(o);
    }
    ll query(int o, int l, int r, int L, int R, int t, int t2) {
        if (l >= L && r <= R) {
            if (t == 0)return minv[o][t2];
            else return maxv[o][t2];
        }
        int m = mid;
        ll ans;
        if (t == 0) {
            ans = INFL;
            if (L <= m)ans = min(ans, query(lson, L, R, t, t2));
            if (R > m)ans = min(ans, query(rson, L, R, t, t2));
        }
        else {
            ans = -INFL;
            if (L <= m)ans = max(ans, query(lson, L, R, t, t2));
            if (R > m)ans = max(ans, query(rson, L, R, t, t2));
        }
        return ans;
    }
    int main() {
        //ios::sync_with_stdio(false); cin.tie(0);
        fin >> n;
        rep(i, 1, n)fin >> a[i];
        rep(i, 1, n)fin >> b[i];
        rep(i, 1, n)s[i] = s[i - 1] + b[i];
        for (int i = n; i >= 1; i--)s2[i] = s2[i + 1] + b[i];
        build(1, 0, n + 1);
        // 左边第一个比当前小
        st[0] = 0;
        rep(i, 1, n) {
            while (top &&a[st[top]] >= a[i])top--;
            l1[i] = st[top];
            st[++top] = i;
        }
        st[0] = n + 1;
        top = 0;
        // 右边第一个比当前小
        for (int i = n; i >= 1; i--) {
            while (top &&a[st[top]] >= a[i])top--;
            r1[i] = st[top];
            st[++top] = i;
        }
        ll ans = -INFL;
        rep(i, 1, n) {
            if (a[i] > 0) {
                ll tmp = a[i] * (s[i] - query(1, 0, n + 1, l1[i], i, 0, 0) +
                    s2[i] - query(1, 0, n + 1, i, r1[i], 0, 1) - b[i]);
                //printf("%d %lld %lld %lld
    ", i, query(1, 0, n + 1, l1[i], i, 0, 0), query(1, 0, n + 1, i, r1[i], 0, 1), (s[i] - query(1, 0, n + 1, l1[i], i, 0, 0) +
                //s2[i] - query(1, 0, n + 1, i, r1[i], 0, 1) - a[i]));
                ans = max(ans, tmp);
            }
            else {
                ll tmp = a[i] * (s[i] - query(1, 0, n + 1, l1[i], i, 1, 0) +
                    s2[i] - query(1, 0, n + 1, i, r1[i], 1, 1) - b[i]);
                //printf("%d %lld %lld %lld
    ", i, query(1, 0, n + 1, l1[i], i, 0, 0), query(1, 0, n + 1, i, r1[i], 0, 1), (s[i] - query(1, 0, n + 1, l1[i], i, 0, 0) +
                //s2[i] - query(1, 0, n + 1, i, r1[i], 0, 1) - a[i]));
                ans = max(ans, tmp);
            }
        }
        cout << ans << '
    ';
        return 0;
    }
    

    D.triples I

    这个题可以往每个二进制位上面去想,会发现有这样一个式子:(2^x)%(3!=0),并且对于一个合法的(a),其二进制个数不会少于(3)
    因为模数为3,所以可以分情况讨论。
    (a)%(3=0)时,答案显然为一个;
    (a)%(3=1)时,由上面(2^x)%(3!=0)可知每个二进制位模(3)要么为1,要么为2,而(a)是所有二进制位加起来,那么凑出3的倍数也就取决于相关二进制的数量了。
    所以就再分类讨论一下:记(cnt_i)表示二进制位模3等于(i)的个数。之后对这个分类讨论一下就行了。
    详见代码吧:

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 64;
    ll a;
    int T;
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> T;
        while(T--) {
            cin >> a;
            if(a % 3 == 0) {
                cout << 1 << ' ' << a << '
    ';
                continue;
            }
            cout << 2 << ' ' ;
            vector <int> v1, v2;
            for(int i = 0; i < N; i++) {
                if(!(a >> i & 1)) continue;
                if((1LL << i) % 3 == 1) v1.push_back(i);
                else v2.push_back(i);
            }
            if(a % 3 == 1) {
                if((int)(v1.size()) >= 2) {
                    cout << a - (1LL << v1[0]) << ' ' << a - (1LL << v1[1]) << '
    ';
                } else if((int)v1.size() == 1) {
                    cout << a - (1LL << v1[0]) << ' ' << (1LL << v1[0]) + (1LL << v2[0]) << '
    ';
                } else {
                    cout << (1LL << v2[0]) + (1LL << v2[1]) + (1LL << v2[2])<< ' ' << a - (1LL << v2[0]) - (1LL << v2[1]) << '
    ';
                }
            } else {
                if((int)(v2.size()) >= 2) {
                    cout << a - (1LL << v2[0]) << ' ' << a - (1LL << v2[1]) << '
    ';
                } else if((int)v2.size() == 1) {
                    cout << a - (1LL << v2[0]) << ' ' << (1LL << v2[0]) + (1LL << v1[0]) << '
    ';
                } else {
                    cout << (1LL << v1[0]) + (1LL << v1[1]) + (1LL << v1[2])<< ' ' << a - (1LL << v1[0]) - (1LL << v1[1]) << '
    ';
                }
            }
        }
        return 0;
    }
    
    

    I.string

    对于一个字符串,如果同时存在(a)(rev(a)),我们只求出本质不同的子串,它们会被算两次,而其余的没有(rev)的就会只算一次。
    但是这个题目中(a)(rev(a))只会被计算一次。但是观察到如果后面拼接一个反串,那么(a)(rev(a))同样被计算两次,而其余的也会被计算两次,但回文串除外。
    那么我们需要做得就是用后缀数组得到拼接过后本质不同的串,但不算上中间拼接字符,设为(p);另外考虑回文串只会被计算一次,所以加上串中回文串的数量(q)。那么最终答案就是(frac{p+q}{2})
    代码如下:

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 4e5 + 5;
    char s[N];
    namespace SA{                                       //sa:1...n  Rank:0...n-1
        int x[N], y[N], sa[N], c[N], height[N], Rank[N];
        int f[N][20], lg[N];
        int n;                                          //length
        void da(char *s, int m){
            n++;
            for(int i = 0; i < m; i++) c[i] = 0;
            for(int i = 0; i < n; i++) c[x[i] = s[i]]++;
            for(int i = 1; i < m; i++) c[i] += c[i - 1] ;
            for(int i = n - 1; i >= 0; i--) sa[--c[x[i]]] = i;
            for(int k = 1; k <= n; k <<= 1) {
                int p = 0 ;
                for(int i = n - k; i < n; i++) y[p++] = i ;
                for(int i = 0; i < n; i++) if(sa[i] >= k) y[p++] =sa[i] - k;
                for(int i = 0; i < m; i++) c[i] = 0;
                for(int i = 0; i < n; i++) c[x[y[i]]]++;
                for(int i = 1; i < m; i++) c[i] += c[i - 1];
                for(int i = n - 1; i >= 0; i--) sa[--c[x[y[i]]]] = y[i] ;
                swap(x , y); p = 1; x[sa[0]] = 0;
                for(int i = 1; i < n; i++)
                    x[sa[i]] = y[sa[i - 1]] == y[sa[i]] && y[sa[i-1] + k] == y[sa[i] + k] ? p - 1 : p++;
                if(p >= n) break ;
                m = p;
            }
            n--;
            int k = 0;
            for(int i = 0; i <= n; i++) Rank[sa[i]] = i;
            for(int i = 0; i < n; i++) {
                if(k) k--;
                int j = sa[Rank[i] - 1];
                while(s[i + k] == s[j + k]) k++;
                height[Rank[i]] = k;
            }
        }
        ll count() {
            ll ans = 0;
            for(int i = 1; i <= n; i++) ans += n - sa[i] - height[i];
            return ans;
        }
        void init() {
            for(int i = 2; i < N; i++) lg[i] = lg[i >> 1] + 1;
            for(int i = 2; i <= n; i++) f[i][0] = height[i];
            for(int j = 1; j < 20; j++)
                for(int i = 2; i + (1 << j) - 1 <= n; i++)
                    f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]) ;
        }
        int get_lcp(int l, int r) {
            if(Rank[l] > Rank[r]) swap(l, r);
            l = Rank[l] + 1, r = Rank[r];
            int k = lg[r - l + 1];
            return min(f[l][k], f[r - (1 << k) + 1][k]);
        }
    }
    namespace PAM{
        int ch[N][26], fail[N], len[N], st[N], cnt[N];
        int sz, n, last;
        int New(int l, int f) {
            memset(ch[++sz], 0, sizeof(ch[sz]));
            len[sz] = l, fail[sz] = f;
            return sz;
        }
        void init() {
            sz = -1;
            New(0, 1); last = New(-1, 0);
            st[n = 0] = -1;
            memset(cnt, 0, sizeof(cnt));
        }
        int getf(int x) {
            while(st[n - len[x] - 1] != st[n]) x = fail[x];
            return x;
        }
        bool Insert(int c) { //int
            st[++n] = c;
            int x = getf(last);
            bool F = 0;
            if(!ch[x][c]) {
                F = 1;
                int f = getf(fail[x]);
                ch[x][c] = New(len[x] + 2, ch[f][c]);
            }
            last = ch[x][c];
            cnt[last] = 1;
            return F;
        }
        void count() {
            for(int i = sz; i >= 1; i--) cnt[fail[i]] += cnt[i];
        }
    };
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> s;
        int n = strlen(s);
        ll ans = 0;
        PAM::init();
        for(int i = 0; i < n; i++) PAM::Insert(s[i] - 'a');
        for(int i = 1; i <= PAM::sz; i++) ans += PAM::cnt[i];
        s[n] = '&';
        for(int i = n + 1; i <= 2 * n; i++) s[i] = s[2 * n - i];
        s[n * 2 + 1] = '';
        SA::n = 2 * n + 1;
        SA::da(s, 520);
        ans += SA::count();
        ans -= 1ll * (n + 1) * (n + 1);
        cout << ans / 2;
        return 0;
    }
    

    J.free

    直接二维状态的dijkstra跑一下就行,转移的时候就类似于dp那样,考虑当前这边是否免费。考场上我zz了枚举了一下,还好数据较小,不然GG。

    Code
    #include <bits/stdc++.h>
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int N = 1e3 + 5;
    int n, m, S, T, k;
    struct edge{
        int u, v, w;
        bool operator < (const edge &A)const {
            return w < A.w;
        }
    }E[N];
    struct Edge{
        int u,v,w,next ;
    }e[N << 1];
    int tot, head[N];
    int W[N][N];
    struct node{
        int d, u, c;
        bool operator < (const node &A)const{
            return d>A.d;
        }
    };
    void adde(int u,int v,int w){
        e[tot].v=v;e[tot].w=w;e[tot].next=head[u];head[u]=tot++;
    }
    int d[N];
    bool vis[N];
    bool Dijkstra(int s){
        priority_queue <node> q; memset(d,INF,sizeof(d));
        memset(vis,0,sizeof(vis));d[s]=0;
        q.push(node{0, s, 0});
        while(!q.empty()){
            node cur = q.top();q.pop();
            int u=cur.u;
            vis[u]=1;
            for(int i=head[u];i!=-1;i=e[i].next){
                int v=e[i].v;
                if(d[v]>d[u]+e[i].w && cur.c + (e[i].w == 0) <= k){
                    d[v]=d[u]+e[i].w;
                    q.push(node{d[v],v, cur.c + (e[i].w == 0)});
                }
            }
        }
        return d[T] != INF;
    }
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> n >> m >> S >> T >> k;
        int tmp = 0;
        for(int i = 1; i <= m; i++) {
            int u, v, w; cin >> u >> v >> w;
            if(u == v) continue;
            if(u > v) swap(u, v);
            if(W[u][v]) W[u][v] = min(W[u][v], w);
            else W[u][v] = w;
        }
        for(int i = 1; i <= n; i++)
            for(int j = i + 1; j <= n; j++)
                if(W[i][j]) E[++tmp] = edge{i, j ,W[i][j]};
        m = tmp;
        sort(E + 1, E + m + 1);
        int ans = INF;
        for(int i = m; i >= 1; i--) {
            memset(head, -1, sizeof(head)); tot = 0;
            for(int j = i; j <= m; j++) {
                adde(E[j].u, E[j].v, 0);
                adde(E[j].v, E[j].u, 0);
            }
            for(int j = 1; j < i; j++) {
                adde(E[j].u, E[j].v, E[j].w);
                adde(E[j].v, E[j].u, E[j].w);
            }
            if(Dijkstra(S)) ans = min(ans, d[T]);
        }
        cout << ans << '
    ';
        return 0;
    }
    

    K.number

    签到题,dp或者维护前缀模3的值都可以做。

    Code
    #include<bits/stdc++.h>
    typedef long long ll;
    const int MAXN = 1e5 + 5, MAXM = 1e5 + 5, INF = 0x3f3f3f3f, MOD = 998244353;
    const ll INFL = 0x3f3f3f3f3f3f3f3f;
    using namespace std;
    const int oo = (1e9) - (1e6);
    #define lson o<<1,l,m
    #define rson o<<1|1,m+1,r
    #define mid l + ((r-l)>>1)
    #define pb push_back
    #define random(a,b) ((a)+rand()%((b)-(a)+1))
    #define all(v) (v.begin(),v.end())
    typedef long double db;
     
    char s[MAXN];
    int n, cnt[MAXN], pre[MAXN];
    int main() {
        cin >> (s + 1);
        n = strlen(s + 1);
        int sum = 0;
        ll ans = 0;
        for (int i = 1; i <= n; i++) {
            sum = (sum * 10 + s[i] - '0') % 300;
            if ((sum - pre[i - 1] * 10 % 300 + 300) % 300 == 0)ans++;
            if (sum == 100)ans += cnt[1];
            else if (sum == 200)ans += cnt[2];
            else if (sum == 0)ans += cnt[0];
            if (i - 1 >= 0)cnt[pre[i - 1] % 3]++;
            pre[i] = sum;
        }
        cout << ans << '
    ';
        return 0;
    }
    
  • 相关阅读:
    盒模型
    DTD
    JS 中的 __proto__ 、prototype、constructor
    ES 5 中 判断数组的方法
    js keyup、keypress和keydown事件
    webpack 安装 url-loader 模块后,图片地址展示错误问题
    前端展示PDF内容
    对象的深拷贝
    IE 11 中不知promise 的 finally 方法
    js判断一个字符串是否为纯数字组成
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11269783.html
Copyright © 2011-2022 走看看