zoukankan      html  css  js  c++  java
  • 2019中国大学生程序设计竞赛(CCPC)

    传送门

    A.^&^

    题意:
    找到最小的正数(C),满足((A xor C)&(B xor C))最小。

    思路:
    输出(A&B)即可,特判答案为0的情况。

    Code
    #include<bits/stdc++.h>
    typedef long long ll;
    typedef unsigned long long ull;
    typedef double db;
    const int MAXN = 1e5+5,MAXM = 2e5+5,MOD = 1e9+7,INF = 0x3f3f3f3f,N = 1e6+1;
    #define lson o<<1,l,m;
    #define rson o<<1|1,m+1,r
    #define mid l + ((r-l)>>1)
    using namespace std;
    
    int t;
    ll A,B;
    int main(){
        ios::sync_with_stdio(false);cin.tie(0);
        cin>>t;
        while(t--){
            cin>>A>>B;
            cout <<max(1LL,(A&B))<<'
    ';
        }
        return 0;
    }
    

    B.array

    题意:
    给出(a_1,cdots, a_n),满足两两各不相同且不超过(n),现有两种操作:

    • ((1,pos)),将(a_{pos})加上(inf)
    • ((2,r,k)),询问超过(k)的,且不等于(a_i,ileq r)的最小整数。

    思路:
    考虑权值线段树,那么对于(geq k)这个条件就很方便处理。
    涉及下标,对于每个结点维护权值出现的位置(每个数出现一次),那么对于第二个限制,答案就为:位置大于(r)的最小的数。
    对于修改操作,直接将位置设置为(inf),表示什么时候都可以用,因为无论这样,这个位置上面的权值都是可以使用的。
    之后在线段树上面查询即可。
    对于第一个条件会划分出(log)个区间,每个区间往下又是(log),所以会有两个(log)
    但其实一个(log)即可,我们往下一次之后,就没必要找其它地方了,并且每次优先考虑往左子树走。

    Code
    #include<bits/stdc++.h>
    typedef long long ll;
    typedef unsigned long long ull;
    typedef double db;
    const int MAXN = 1e5+5,MAXM = 2e5+5,MOD = 1e9+7,INF = 0x3f3f3f3f,N = 1e6+1;
    #define lson o<<1,l,m
    #define rson o<<1|1,m+1,r
    #define mid l + ((r-l)>>1)
    using namespace std;
    
    int t,n,m,a[MAXN],p[MAXN],maxv[MAXN<<2];
    inline void pushUp(int o){
        maxv[o] = max(maxv[o<<1],maxv[o<<1|1]);
    }
    void build(int o,int l,int r){
        if(l==r){
            maxv[o] = p[l];
            return ;
        }
        int m = mid;
        build(lson);build(rson);
        pushUp(o);
    }
    void update(int o,int l,int r,int p){
        if(l==r){
            maxv[o] = INF;
            return ;
        }
        int m = mid;
        if(p<=m)update(lson,p);
        else update(rson,p);
        pushUp(o);
    }
    int query2(int o,int l,int r,int v){
        if(l==r){
            if(maxv[o]>v)return l;
            else return INF;
        }
        int m = mid;
        if(maxv[o<<1]>v)return query2(lson,v);
        else return query2(rson,v);
    }
    int query(int o,int l,int r,int v,int k){
        if(l>=k){
            return query2(o,l,r,v);
        }
        int m = mid;
        int ans = query(rson,v,k);
        if(k<=m){
            ans = min(ans,query(lson,v,k));
        }
        return ans;
    }
    int main(){
        ios::sync_with_stdio(false);cin.tie(0);
        cin>>t;
        while(t--){
            cin>>n>>m;
            for(int i=1;i<=n;i++)cin>>a[i],p[a[i]]=i;
            p[n+1] = INF;
            build(1,1,n+1);
            int op,r,k,lastans=0;
            while(m--){
                cin>>op;
                if(op==1){
                    cin>>r;
                    r^=lastans;
                    r = a[r];
                    update(1,1,n+1,r);
                }else{
                    cin>>r>>k;
                    r^=lastans;k^=lastans;
                    //cout <<r<<' '<<k<<'
    ';
                    lastans = query(1,1,n+1,r,k);
                    cout <<lastans<<'
    ';
                }
            }
        }
        return 0;
    }
    

    C.K-th occurrence

    题意:
    给出一个字符串(S),回答多个询问:((l,r,k)),即(s_lcdots s_r)(k)次出现的位置。

    思路:
    对于处理多个相同子串的问题,可以考虑后缀数组。
    然后这题挺考察对后缀数组的理解程度的。

    • 对于(s_l),通过(Rank[l])找到其在(sa)数组中的位置(pos);
    • 通过(pos)向前向后找尽可能长的区间,满足(lcpgeq r-l+1),那么就知道所有的子串个数且其后缀排名;
    • 但这样无法快速知道原串中第(k)出现的位置;
    • 问题等价于区间查询第(k)大;
    • 主席树!
    • 结点维护原位置信息就行,也就是(sa)数组。

    稍微有点细节,详见代码:

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e5 + 5;
    int T, n, q;
    char s[N];
    struct 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) {
            ++l; if(l > r) return n + 1;
            int k = lg[r - l + 1];
            return min(f[l][k], f[r - (1 << k) + 1][k]);
        }
    }suf;
    int rt[N * 22], ls[N * 22], rs[N * 22], sumv[N * 22];
    int tot;
    void build(int &o, int l, int r) {
        o = ++tot;
        ls[o] = rs[o] = sumv[o] = 0;
        if(l == r) return;
        int mid = (l + r) >> 1;
        build(ls[o], l, mid); build(rs[o], mid + 1, r);
    }
    void insert(int &o, int last, int l, int r, int v) {
        o = ++tot;
        sumv[o] = sumv[last] + 1;
        ls[o] = ls[last]; rs[o] = rs[last];
        if(l == r) return;
        int mid = (l + r) >> 1;
        if(v <= mid) insert(ls[o], ls[last], l, mid, v);
        else insert(rs[o], rs[last], mid + 1, r, v);
    }
    int query(int o, int last, int l, int r, int k) {
        if(l == r) return l;
        int mid = (l + r) >> 1;
        int sz = sumv[ls[o]] - sumv[ls[last]];
        if(sz >= k) return query(ls[o], ls[last], l, mid, k);
        else return query(rs[o], rs[last], mid + 1, r, k - sz);
    }
    int getl(int p, int sz) {
        int l = 1, r = p + 1, mid;
        while(l < r) {
            mid = (l + r) >> 1;
            if(suf.get_lcp(mid, p) >= sz) r = mid;
            else l = mid + 1;
        }
        return l;
    }
    int getr(int p, int sz) {
        int l = p, r = n + 1, mid;
        while(l < r) {
            mid = (l + r) >> 1;
            int tmp = suf.get_lcp(p, mid);
            if(suf.get_lcp(p, mid) >= sz) l = mid + 1;
            else r = mid;
        }
        return r - 1;
    }
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> T;
        while(T--) {
            cin >> n >> q;
            cin >> s;
            suf.n = n;
            suf.da(s, 520);
            suf.init();
            tot = 0;
            build(rt[0], 0, n);
            for(int i = 1; i <= n; i++) {
                insert(rt[i], rt[i - 1], 0, n, suf.sa[i]);
            }
            while(q--) {
                int l, r, k; cin >> l >> r >> k;
                --l, --r;
                int pos = suf.Rank[l];
                int ll = getl(pos, r - l + 1);
                int rr = getr(pos, r - l + 1);
                if(rr - ll + 1 < k) {
                    cout << -1 << '
    ';
                } else {
                    cout << query(rt[rr], rt[ll - 1], 0, n, k) + 1 << '
    ';
                }
            }
        }
        return 0;
    }
    

    D.path

    题意:
    给出一个有向图,有(q)次询问,对于每次询问,输出其第(k)小路径。
    (n,m,q,kleq 5*10^4)

    思路:

    • 最直接的想法,直接贪心(bfs),加入所有边!
    • 很轻松就会被hack,比如菊花图。
    • 考虑减枝?但会影响正确性...似乎将上界设松一点可以过
    • 是否一次需要加入所有边?显然不是,但肯定要加入最小的边。
    • 考虑细化贪心,原来的贪心可能会加入很多没用的。
    • 对于条边,扩展两种状态:加上最小的一条边,或者换成次大的边。

    这样就能枚举到所有的状态了。跟有一次牛客最小团的一个题比较类似。

    Code
    #include <bits/stdc++.h>
    //#define heyuhhh ok
    #define MP make_pair
    #define sz(g) (int)g.size()
    #define fi first
    #define se second
    #define INF 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    typedef pair<int, int> pii;
    const int N = 1e5 + 5;
    int T, n, m, Q;
    vector <pii> g[N];
    int query[N];
    ll res[N];
    struct node{
        int from, e;
        ll dis;
        bool operator < (const node &A) const {
            return dis > A.dis;
        }
    };
    int main() {
    #ifdef heyuhhh
        freopen("input.in", "r", stdin);
    #else
        ios::sync_with_stdio(false); cin.tie(0);
    #endif
        cin >> T; ;
        while(T--) {
            cin >> n >> m >> Q;
            for(int i = 1; i <= n; i++) g[i].clear();
            for(int i = 1; i <= m; i++) {
                int u, v, w; cin >> u >> v >> w;
                g[u].push_back(MP(v, w));
            }
            for(int i = 1; i <= n; i++) {
                sort(g[i].begin(), g[i].end(), [&](pii A, pii B) {
                    return A.se < B.se;
                });
            }
            int MAX = 0, cnt = 0;
            for(int i = 1; i <= Q; i++) cin >> query[i], MAX = max(MAX, query[i]);
            priority_queue <node> q;
            for(int i = 1; i <= n; i++) {
                if(sz(g[i])) q.push(node{i, 0, g[i][0].se});
            }
            while(!q.empty()) {
                node cur = q.top(); q.pop();
                res[++cnt] = cur.dis;
                if(cnt > MAX) break;
                int u = cur.from, e = cur.e;
                if(e + 1 < sz(g[u])) {
                    q.push(node{u, e + 1, cur.dis - g[u][e].se + g[u][e + 1].se});
                }
                int v = g[u][e].fi;
                if(sz(g[v])) q.push(node{v, 0, cur.dis + g[v][0].se});
            }
            for(int i = 1; i <= Q; i++) {
                cout << res[query[i]] << '
    ';
            }
        }
        return 0;
    

    E.huntian oy

    题意:
    定义(f(n,a,b)=sum_{i=1}^nsum_{j=1}^igcd(i^a-j^a,i^b-j^b)[gcd(i,j)=1]\% 10^9+7)
    先有(T)组询问,每组询问给出(n,a,b),求(f(n,a,b))

    思路:
    先有一个公式如下:
    (ageq b),且(a,b)互质,则有:

    [egin{aligned} &gcd(a^n-b^n,a^m-b^m)\ =&gcd(a^m-b^m,a^{n\%m}-b^{n\%m})=a^{gcd(n,m)}-b^{gcd(n,m)} end{aligned} ]

    我也不知道这咋证= =
    反正有了这个式子之后就好推了:

    [egin{aligned} f(n,a,b)=&sum_{i=1}^n sum_{j=1}^i i-j[gcd(i,j)=1]\ =&sum_{i=1}^n sum_{j=1}^i i[gcd(i,j)=1]-sum_{i=1}^n sum_{j=1}^i j[gcd(i,j)=1]\ =&sum_{i=1}^nivarphi(i)-sum_{i=1}^nfrac{ivarphi(i)+[i=1]}{2} end{aligned} ]

    至于为什么后面那部分可以化成这样,这涉及到(gcd(n,m)=gcd(n-m,n)),也就是说,与之互素的数是成对出现的,并且其和为(n)。当然(n=1)的情况除外。
    之后式子就可以化为这样:

    [f(n,a,b)=frac{1}{2}sum_{i=1}^nivarphi(i)-1 ]

    之后直接上杜教筛就是了。

    Code
    #include <bits/stdc++.h>
    #define heyuhhh ok
    using namespace std;
    typedef long long ll;
    const int N = 5e6 + 5, MOD = 1e9 + 7, inv6 = 166666668;
    int p[N];
    ll phi[N];
    bool chk[N];
    unordered_map <int, int> mp;
    inline void init() {
        phi[1] = 1;
        int cnt = 0, k = N - 1, i;
        for(i = 2; i <= k; ++i) {
            if(!chk[i]) p[++cnt] = i, phi[i] = i - 1;
            for(int j = 1; j <= cnt && i * p[j] <= k; j++) {
                chk[i * p[j]] = 1;
                if(i % p[j] == 0) {phi[i * p[j]] = phi[i] * p[j]; break;}
                phi[i * p[j]] = phi[i] * (p[j] - 1);
            }
        }
        for(i = 1; i < N; ++i) {
            phi[i] = phi[i - 1] + 1ll * i * phi[i];
            if(phi[i] >= MOD) phi[i] %= MOD;
        }
    }
    
    int djs_phi(int n) {
        if(n <= 5000000) return phi[n];
        if(mp[n]) return mp[n];
        int ans = 1ll * (n + 1) * n % MOD * (2ll * n + 1) % MOD * inv6 % MOD;
        for(register int i = 2, j; i <= n; i = j + 1) {
            j = n / (n / i);
            ans -= ((ll(j - i + 1) * (j + i)) >> 1) % MOD * (ll)djs_phi(n / i) % MOD;
            ans %= MOD;
        }
        if(ans < 0) ans += MOD;
        return mp[n] = ans;
    }
    int n, a, b, T;
    int main() {
    #ifdef heyuhhh
        freopen("input.in", "r", stdin);
    #else
        ios::sync_with_stdio(false); cin.tie(0);
    #endif
        init();
        cin >> T;
        while(T--) {
            cin >> n >> a >> b;
            int ans = djs_phi(n) - 1;
            ans = (1ll * ans * (MOD + 1) / 2) % MOD;
            cout << ans << '
    ';
        }
        return 0;
    }
    
    
    ## F.Shuffle Card 题意: 给出$n$张不同的牌,有$m$次操作,每次操作拿出一张牌放到最前面。 问最后牌的状态是什么。

    思路:
    考虑倒序操作即可。

    Code
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 1e5 + 5;
    int n, m;
    int a[N], b[N], c[N];
    bool vis[N];
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        cin >> n >> m;
        vector <int> ans;
        for(int i = 1; i <= n; i++) cin >> a[i];
        for(int i = 1; i <= m; i++) cin >> b[i];
        int now = 0;
        for(int i = m; i >= 1; i--) {
            if(!vis[b[i]]) {
                vis[b[i]] = 1;
                c[++now] = b[i];
            }
        }
        for(int i = 1; i <= n; i++) if(!vis[a[i]]) c[++now] = a[i];
        for(int i = 1; i <= now; i++) cout << c[i] << ' ';
        return 0;
    }
    

    G.Windows Of CCPC

    没什么好说的,递归处理即可。

    Code
    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<vector>
    #include<cassert>
    #define REP(r,x,y) for(register int r=(x); r<(y); r++)
    #define REPE(r,x,y) for(register int r=(x); r<=(y); r++)
    #ifdef sahdsg
    #define DBG(...) printf(__VA_ARGS__)
    #else
    #define DBG(...) void(0)
    #endif
    using namespace std;
    
    int _s; char _c;
    template <class T>
    void read(T&x) {
        x=0; do _c=getchar(); while(!isdigit(_c) && _c!='-'); _s=1; if(_c=='-') _s=-1, _c=getchar(); while(isdigit(_c)) { x=x*10+_c-'0'; _c=getchar();} x*=_s;
    }
    
    typedef long long LL;
    #define MAXN 1000007
    char ans[15][1028][1028];
    int main() {
        ans[0][0][0]='C', ans[0][0][1]='C', ans[0][1][0]='P', ans[0][1][1]='C';
        REP(r,0,10)
        REP(i,0,1<<(r+1)) {
            REP(j,0,1<<(r+1)) {
                if(ans[r][i][j]=='C') {
                    ans[r+1][i*2][j*2]='C', ans[r+1][i*2][j*2+1]='C';
                    ans[r+1][i*2+1][j*2]='P', ans[r+1][i*2+1][j*2+1]='C';
                } else {
                    ans[r+1][i*2][j*2]='P', ans[r+1][i*2][j*2+1]='P';
                    ans[r+1][i*2+1][j*2]='C', ans[r+1][i*2+1][j*2+1]='P';
                }
            }
        }
        int T; read(T);
        while(T--) {
            int k; read(k); k--;
            DBG("!%d
    ", k);
            REP(i,0,1<<(k+1))    {
                   REP(j,0,1<<(k+1)){
                    //assert(ans[k][i][j]>' ');
                    putchar(ans[k][i][j]);
                }
                putchar('
    ');
            }
        }
        return 0;
    }
    

    H.Fishing Master

    贪心处理,队友写的,没有看。
    反正能不浪费时间就不浪费时间。

    Code
    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #include<cstring>
    #include<string>
    #include<vector>
    #include<queue>
    #define REP(r,x,y) for(register int r=(x); r<(y); r++)
    #define REPE(r,x,y) for(register int r=(x); r<=(y); r++)
    #ifdef sahdsg
    #define DBG(...) printf(__VA_ARGS__)
    #else
    #define DBG(...) void(0)
    #endif
    using namespace std;
    
    int _s; char _c;
    template <class T>
    void read(T&x) {
        x=0; do _c=getchar(); while(!isdigit(_c) && _c!='-'); _s=1; if(_c=='-') _s=-1, _c=getchar(); while(isdigit(_c)) { x=x*10+_c-'0'; _c=getchar();} x*=_s;
    }
    
    typedef long long LL;
    #define MAXN 100007
    struct node {
        int v, r;
        bool operator<(const node &rt) const {
            return v<rt.v;
        }
    };
    priority_queue<node> q;
    int t[MAXN];
    int main() {
        int T; read(T);
        while(0<T--) {
            while(!q.empty()) q.pop();
            int n,k; read(n); read(k);
            LL ans=(LL)k*n;
            REP(i,0,n) {
                read(t[i]);
            }
            REP(i,0,n) {
                ans+=t[i];
                q.push((node){min(k,t[i]),t[i]-k});
            }
            REP(i,1,n) {
                node now=q.top(); q.pop();
                ans-=now.v;
                if(now.r>0)
                    q.push((node){min(k,now.r),now.r-k});
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }
    
  • 相关阅读:
    JQuery之在线引用
    SpringBoot之durid连接池配置
    VueJs之事件处理器
    VueJs之样式绑定
    VueJs之判断与循环监听
    PTA 7-8 暴力小学(二年级篇)-求出4个数字 (10分)
    PTA 7-7 交替字符倒三角形 (10分)
    PTA 7-5 阶乘和 (10分)
    PTA 7-4 哥德巴赫猜想 (10分)
    PTA 7-3 可逆素数 (15分)
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11404966.html
Copyright © 2011-2022 走看看