• Educational Codeforces Round 36


    Educational Codeforces Round 36 

    D. Almost Acyclic Graph

    首先想到枚举所有的边,然后判断删掉之后是否还有环,这样的话复杂度会到(O(m^2)),发现(n)很小,那么最大的环大小不会超过(n),所以考虑找到一个环,然后枚举环上的边删掉之后判断是否还有环

    判环可以用拓扑排序来做

    view code
    #pragma GCC optimize("O3")
    #pragma GCC optimize("Ofast,no-stack-protector")
    #include<bits/stdc++.h>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define endl "
    "
    #define LL long long int
    #define vi vector<int>
    #define vl vector<LL>
    #define all(V) V.begin(),V.end()
    #define sci(x) scanf("%d",&x)
    #define scl(x) scanf("%I64d",&x)
    #define scs(s) scanf("%s",s)
    #define pii pair<int,int>
    #define pll pair<LL,LL>
    #ifndef ONLINE_JUDGE
    #define cout cerr
    #endif
    #define cmax(a,b) ((a) = (a) > (b) ? (a) : (b))
    #define cmin(a,b) ((a) = (a) < (b) ? (a) : (b))
    #define debug(x)  cerr << #x << " = " << x << endl
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    template <typename T> vector<T>& operator << (vector<T> &__container, T x){ __container.push_back(x); return __container; }
    template <typename T> ostream& operator << (ostream &out, vector<T> &__container){ for(T _ : __container) out << _ << ' '; return out; }
    const int MAXN = 5e2+7;
    vi G[MAXN];
    bool vis[MAXN], instk[MAXN];
    stack<int> stk;
    vector<int> vec;
    void dfs(int u){
        vis[u] = true;
        stk.push(u);
        instk[u] = true;
        for(int v : G[u]){
            if(!vis[v]) dfs(v);
            else if(instk[v]){
                do{
                    vec << stk.top();
                    stk.pop();
                }while(vec.back()!=v);
                reverse(all(vec));
            }
            if(!vec.empty()) return;
        }
        instk[u] = false;
        stk.pop();
    }
    void solve(){
        int n, m;
        sci(n); sci(m);
        for(int i = 1; i <= m; i++){
            int u, v; sci(u); sci(v);
            G[u] << v;
        }
        for(int i = 1; i <= n; i++) if(!vis[i]){
            dfs(i);
            if(!vec.empty()) break;
        }
        if(vec.empty()){
            cout << "YES" << endl;
            return;
        }
        bool ok = false;
        auto test = [&](int a, int b){
            vi deg(n+1,0);
            for(int i = 1; i <= n; i++) for(int v : G[i]){
                if(i==a and v==b) continue;
                deg[v]++;
            }
            int used = 0;
            queue<int> que;
            for(int i = 1; i <= n; i++) if(!deg[i]) que.push(i);
            while(!que.empty()){
                int u = que.front();
                que.pop(), used++;
                for(int v : G[u]){
                    if(u==a and v==b) continue;
                    if(!--deg[v]) que.push(v);
                }
            }
            return used==n;
        };
        for(int i = 0; i < vec.size() - 1; i++){
            if(test(vec[i],vec[i+1])){
                ok = true;
                break;
            }
        }
        if(test(vec.back(),vec.front())) ok = true;
        cout << (ok ? "YES" : "NO") << endl;
    }
    int main(){
        #ifndef ONLINE_JUDGE
        freopen("Local.in","r",stdin);
        freopen("ans.out","w",stdout);
        #endif
        solve();
        return 0;
    }
    

    E. Physical Education Lessons

    那么对于这种区间范围很大的数据结构题,一般离散化之后用线段树来做,或者动态开点线段树

    这里考虑离散化之后用线段树来做,注意把每个要离散化点的右端点也加进去,保证这个点在线段树上的区间范围是(1)

    view code
    #pragma GCC optimize("O3")
    #pragma GCC optimize("Ofast,no-stack-protector")
    #include<bits/stdc++.h>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define endl "
    "
    #define LL long long int
    #define vi vector<int>
    #define vl vector<LL>
    #define all(V) V.begin(),V.end()
    #define sci(x) scanf("%d",&x)
    #define scl(x) scanf("%I64d",&x)
    #define scs(s) scanf("%s",s)
    #define pii pair<int,int>
    #define pll pair<LL,LL>
    #ifndef ONLINE_JUDGE
    #define cout cerr
    #endif
    #define cmax(a,b) ((a) = (a) > (b) ? (a) : (b))
    #define cmin(a,b) ((a) = (a) < (b) ? (a) : (b))
    #define debug(x)  cerr << #x << " = " << x << endl
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    template <typename T> vector<T>& operator << (vector<T> &__container, T x){ __container.push_back(x); return __container; }
    template <typename T> ostream& operator << (ostream &out, vector<T> &__container){ for(T _ : __container) out << _ << ' '; return out; }
    const int MAXN = 1.2e6+7;
    int n, q;
    vector<int> vec;
    struct STA{
        int l, r, k;
    }sta[MAXN];
    struct SegmentTree{
        int l[MAXN<<2], r[MAXN<<2], sum[MAXN<<2], lazy[MAXN<<2];
        #define ls(rt) rt << 1
        #define rs(rt) rt << 1 | 1
        #define pushup(rt) sum[rt] = sum[ls(rt)] + sum[rs(rt)]
        void build(int L, int R, int rt = 1){
            l[rt] = L; r[rt] = R;
            lazy[rt] = -1;
            if(L + 1 == R){
                sum[rt] = vec[r[rt]] - vec[l[rt]];
                return;
            }
            int mid = (L + R) >> 1;
            build(L,mid,ls(rt)); build(mid,R,rs(rt));
            pushup(rt);
        }
        void pushdown(int rt){
            if(lazy[rt]==-1) return;
            lazy[ls(rt)] = lazy[rs(rt)] = lazy[rt];
            if(lazy[rt]==1){
                sum[ls(rt)] = vec[r[ls(rt)]] - vec[l[ls(rt)]];
                sum[rs(rt)] = vec[r[rs(rt)]] - vec[l[rs(rt)]];
            }else sum[ls(rt)] = sum[rs(rt)] = 0;
            lazy[rt] = -1;
            return;
        }
        void modify(int L, int R, int x, int rt = 1){
            if(L>=r[rt] or l[rt]>=R) return;
            if(L<=l[rt] and r[rt]<=R){
                lazy[rt] = x;
                if(x==1) sum[rt] = vec[r[rt]] - vec[l[rt]];
                else sum[rt] = 0;
                return;
            }
            pushdown(rt);
            modify(L,R,x,ls(rt)); modify(L,R,x,rs(rt));
            pushup(rt);
        }
        int query(int L, int R, int rt = 1){
            if(L>=r[rt] or l[rt]>=R) return 0;
            if(L<=l[rt] and r[rt]<=R) return sum[rt];
            pushdown(rt);
            return query(L,R,ls(rt)) + query(L,R,rs(rt));
        }
    }ST;
    void solve(){
        sci(n); sci(q);
        for(int i = 1; i <= q; i++){
            sci(sta[i].l); sci(sta[i].r); sci(sta[i].k);
            vec << sta[i].l << sta[i].r;
            if(sta[i].l+1<=n) vec << sta[i].l+1;
            if(sta[i].r+1<=n) vec << sta[i].r+1;
        }
        sort(all(vec)); vec.erase(unique(all(vec)),vec.end());
        vec.push_back(vec.back()+1);
        for(int i = 1; i <= q; i++){
            sta[i].l = lower_bound(all(vec),sta[i].l) - vec.begin();
            sta[i].r = lower_bound(all(vec),sta[i].r) - vec.begin();        
        }
        int ret = n;
        ST.build(0,vec.size()-1);
        for(int i = 1; i <= q; i++){
            int k = sta[i].k, l = sta[i].l, r = sta[i].r;
            ret -= ST.query(l,r+1); 
            ST.modify(l,r+1,k-1);
            if(k==2) ret += vec[r] - vec[l] + 1;
            cout << ret << endl;
        }
    }
    int main(){
        #ifndef ONLINE_JUDGE
        freopen("Local.in","r",stdin);
        freopen("ans.out","w",stdout);
        #endif
        solve();
        return 0;
    }
    

    F. Imbalance Value of a Tree

    首先,可以把问题转化为任意两点间最大值的和减去最小值的和

    以最大值为例,最小值类似

    考虑类似点分治的思想,每次找到所有点中的最大值,然后计算这个点的贡献就是经过这个点的所有路径的数量乘上点权,然后把这个点删掉之后变成几个子树,分治解决,但是每次找到的点不是树的重心,所以分治复杂度最坏会到达(O(n^2))

    考虑反着来做,每次找到当前最小的点,然后把连着的所有比他小的点都连起来,然后算当前连通块的贡献,可以用并查集来做,复杂度为(O(nlog n))

    对于某个连通块,假设当前的最大值点为(u),那么路径的总数应该等于任意两个子树的大小的乘积加上总的大小,前者可以用前缀和来优化计算

    view code
    #pragma GCC optimize("O3")
    #pragma GCC optimize("Ofast,no-stack-protector")
    #include<bits/stdc++.h>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define endl "
    "
    #define LL long long int
    #define vi vector<int>
    #define vl vector<LL>
    #define all(V) V.begin(),V.end()
    #define sci(x) scanf("%d",&x)
    #define scl(x) scanf("%I64d",&x)
    #define scs(s) scanf("%s",s)
    #define pii pair<int,int>
    #define pll pair<LL,LL>
    #ifndef ONLINE_JUDGE
    #define cout cerr
    #endif
    #define cmax(a,b) ((a) = (a) > (b) ? (a) : (b))
    #define cmin(a,b) ((a) = (a) < (b) ? (a) : (b))
    #define debug(x)  cerr << #x << " = " << x << endl
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    template <typename T> vector<T>& operator << (vector<T> &__container, T x){ __container.push_back(x); return __container; }
    template <typename T> ostream& operator << (ostream &out, vector<T> &__container){ for(T _ : __container) out << _ << ' '; return out; }
    const int MAXN = 1e6+7;
    int n, app[MAXN], root[MAXN], sz[MAXN];
    pair<pii,int> w[MAXN], cp[MAXN];
    vi G[MAXN];
    int findx(int x){ return x==root[x]?x:root[x]=findx(root[x]); }
    
    
    void solve(){
        sci(n);
        for(int i = 1; i <= n; i++){
            sci(w[i].first.first);
            w[i].first.second = ++app[w[i].first.first];
            w[i].second = i;
            cp[i] = w[i];
        }
        for(int i = 1; i < n; i++){
            int u, v;
            sci(u); sci(v);
            G[u] << v; G[v] << u;
        }
        sort(cp+1,cp+1+n);
        LL ret = 0;
        for(int i = 1; i <= n; i++) sz[i] = 1, root[i] = i;
        for(int i = 1; i <= n; i++){
            vi vec, sum;
            int u = cp[i].second;
            for(int v : G[u]){
                if(w[v].first < w[u].first){
                    vec << sz[findx(v)];
                    sz[findx(u)] += sz[findx(v)];
                    root[findx(v)] = findx(u);
                }
            }
            partial_sum(all(vec),back_inserter(sum));
            LL tot = 0;
            for(int j = 1; j < vec.size(); j++) tot += 1ll * vec[j] * sum[j-1];
            tot += sz[findx(u)];
            ret += w[u].first.first * tot;
        }
        for(int i = 1; i <= n; i++) sz[i] = 1, root[i] = i;
        for(int i = n; i >= 1; i--){
            vi vec, sum;
            int u = cp[i].second;
            for(int v : G[u]){
                if(w[v].first > w[u].first){
                    vec << sz[findx(v)];
                    sz[findx(u)] += sz[findx(v)];
                    root[findx(v)] = findx(u);
                }
            }
            partial_sum(all(vec),back_inserter(sum));
            LL tot = 0;
            for(int j = 1; j < vec.size(); j++) tot += 1ll * vec[j] * sum[j-1];
            tot += sz[findx(u)];
            ret -= w[u].first.first * tot;
        }
        cout << ret << endl;
    }
    int main(){
        #ifndef ONLINE_JUDGE
        freopen("Local.in","r",stdin);
        freopen("ans.out","w",stdout);
        #endif
        solve();
        return 0;
    }
    

    G. Coprime Arrays

    要计算(sum_{i=1}^k (sum_{a_1=1}^icdots sum_{a_n=1}^i[operatorname {gcd}(a_1cdots a_n)=1])oplus i)

    考虑单独计算(g(i) = sum_{a_1=1}^icdots sum_{a_n=1}^i[operatorname {gcd}(a_1cdots a_n)=1])

    通过莫比乌斯反演可以得到:(g(i) = sum_{a_1=1}^icdots sum_{a_n=1}^i[operatorname {gcd}(a_1cdots a_n)=1] = sum_{j=1}^imu(j)cdot lfloor frac ij floor^n)

    如果直接用整除分块来做的话,复杂度是(O(sum_{i=1}^ksqrt i) = O(frac 23 k^{frac 32}))

    考虑相邻两个(g(i),g(i-1))可以发现只有满足(jmid i)(lfloor frac ij floor)发生了变化,所以考虑计算(f(i) = g(i)-g(i-1)),所有数的因子数的复杂度为(O(klog k)),再预处理一下所有的幂,总复杂度为(O(k(log n + log k)))

    view code
    #pragma GCC optimize("O3")
    #pragma GCC optimize("Ofast,no-stack-protector")
    #include<bits/stdc++.h>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define endl "
    "
    #define LL long long int
    #define vi vector<int>
    #define vl vector<LL>
    #define all(V) V.begin(),V.end()
    #define sci(x) scanf("%d",&x)
    #define scl(x) scanf("%I64d",&x)
    #define scs(s) scanf("%s",s)
    #define pii pair<int,int>
    #define pll pair<LL,LL>
    #ifndef ONLINE_JUDGE
    #define cout cerr
    #endif
    #define cmax(a,b) ((a) = (a) > (b) ? (a) : (b))
    #define cmin(a,b) ((a) = (a) < (b) ? (a) : (b))
    #define debug(x)  cerr << #x << " = " << x << endl
    function<void(void)> ____ = [](){ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);};
    template <typename T> vector<T>& operator << (vector<T> &__container, T x){ __container.push_back(x); return __container; }
    template <typename T> ostream& operator << (ostream &out, vector<T> &__container){ for(T _ : __container) out << _ << ' '; return out; }
    const int MAXN = 2e6+7;
    const int MOD = 1e9+7;
    int mu[MAXN], prime[MAXN], pri_cnt, pw[MAXN];
    int f[MAXN];
    bool npm[MAXN];
    LL ksm(LL a, LL b){
        LL ret = 1;
        while(b){
            if(b&1) ret = ret * a % MOD;
            b >>= 1;
            a = a * a % MOD;
        }
        return ret;
    }
    void sieve(){
        mu[1] = 1;
        for(int i = 2; i < MAXN; i++){
            if(!npm[i]) prime[++pri_cnt] = i, mu[i] = -1;
            for(int j = 1; i * prime[j] < MAXN; j++){
                npm[i*prime[j]] = true;
                if(i%prime[j]==0){
                    mu[i*prime[j]] = 0;
                    break;
                }
                mu[i*prime[j]] = -mu[i];
            }
        }
    }
    void solve(){
        sieve();
        int n, k;
        sci(n); sci(k);
        for(int i = 1; i <= k; i++) pw[i] = ksm(i,n);
        for(int i = 1; i <= k; i++) for(int j = i; j <= k; j += i) f[j] = (f[j] + mu[i] * (pw[j/i] - pw[j/i-1])) % MOD;
        int ret = 0, cur = 0;
        for(int i = 1; i <= k; i++){
            cur = ((cur + f[i]) % MOD + MOD) % MOD;
            ret = (ret + (cur ^ i)) % MOD;
        }
        cout << ret << endl;
    }
    int main(){
        #ifndef ONLINE_JUDGE
        freopen("Local.in","r",stdin);
        freopen("ans.out","w",stdout);
        #endif
        solve();
        return 0;
    }
    
  • 相关阅读:
    python_3 装饰器之初次见面
    python_迭代器
    Python_1生成器(下)之单线并行--生产着消费者模型
    Python_ 1生成器(上)初识生成器
    memcache 和 redis 的区别
    Linux 面试总结
    网络面试总结
    操作系统相关面试总结
    剑指offer 数组中的重复数字
    svn-主副分支使用
  • 原文地址:https://www.cnblogs.com/kikokiko/p/13590621.html
Copyright © 2020-2023  润新知