zoukankan      html  css  js  c++  java
  • 「SRM786」题解

    昨天打完牛客挑战赛意识模糊忘记 register 了...一看题目发现血亏。

    250pts

    我们将下标按照 (mod k) 分组 发现每个组之间的交换互不影响。每次交换相当于至少要减少一对顺序对。我们肯定是想每次只减少一个顺序对(这样这一组的答案就是顺序对个数了)。发现我们每次交换相邻两个顺序对就满足条件。所以答案就是每组的顺序对个数加起来。

    一开始 zz 了想错了 但是感觉 10 min是能做完的?

    #include<bits/stdc++.h>
    
    #define fi first
    #define se second
    #define U unsigned
    #define LL long long
    #define pb push_back
    #define MP std::make_pair
    #define all(x) x.begin(),x.end()
    #define CLR(i,a) memset(i,a,sizeof(i))
    #define FOR(i,a,b) for(int i = a;i <= b;++i)
    #define ROF(i,a,b) for(int i = a;i >= b;--i)
    #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
    
    const int MAXN = 2e5 + 5;
    const int MAXM = 233;
    
    struct BIT{
        #define lowbit(x) ((x)&(-(x)))
        int tree[MAXM];
    
        inline void add(int pos,int x){
            while(pos < MAXM){
                tree[pos] += x;
                pos += lowbit(pos);
            }
        }
    
        inline int query(int pos){
            int res = 0;
            while(pos){
                res += tree[pos];
                pos -= lowbit(pos);
            }
            return res;
        }
    }bit;
    
    class SwapTheString {
        int A[MAXN];
        int f[MAXN][26];
        std::string str;
        public:
        long long findNumberOfSwaps(std::string P, int A0, int X, int Y, int N, int K) {
            A[0] = A0;
            FOR(i,1,N-1) A[i] = (1ll*A[i-1]*X+Y)%1812447359;
            str = P;str.resize(N);
            FOR(i,P.length(),N-1) str[i] = (char)(A[i]%26+'a');
            if(K >= N) return 0;
            LL ans = 0;
            FOR(i,0,K-1){
                CLR(bit.tree,0);
                for(int t=0,j = i;j < N;j += K,++t){
                    ans += bit.query(str[j]-1);
                    bit.add(str[j],1);
                }
            }
            return ans;
        }
    };
    

    500pts

    这种题目 数字种类数不多 可以用期望线性性拆成计算每个数字对答案的贡献的期望

    (f[i][j]) 表示经过了 (i) 轮 数组 (j) 的期望出现次数。第二维是在 (mod 512) 意义下定义的。

    显然有转移 (f[i][j] = frac{n-1}{n}f[i-1][j]+frac{1}{n}f[i-1][j-1])

    就是有 (frac{f[i][j-1]}{n}) 的概率让出现次数 (+1),有(frac{f[i-1][j]}{n}) 的概率让出现次数 (-1)。直接做的时间复杂度是 (O(512*K)) 看起来就不太行。

    于是我们考虑使用矩阵快速幂 可以做到 (O(512^3 log K)) 然而还是过不去。

    继续观察:发现转移矩阵是一个循环矩阵 矩阵乘法改成暴力循环卷积/FFT优化到 (O(512^2log K)/ O(512log512log K))

    如果这个题是输出小数的话或许可以代入单位根插值(个人感觉精度会丢的很厉害)

    这个题被搞了 原因是我不知道 class 里的变量初始化在 Linux 下是随机值(也不知道 Mac 到底是随 Win 还是随 Linux)。否则估计花 20min 就可以。(归根结底还是自己菜)

    #include<bits/stdc++.h>
    
    #define fi first
    #define se second
    #define U unsigned
    //#define P stdd::pair<int,int>
    #define LL long long
    #define pb push_back
    #define MP std::make_pair
    #define all(x) x.begin(),x.end()
    #define CLR(i,a) memset(i,a,sizeof(i))
    #define FOR(i,a,b) for(int i = a;i <= b;++i)
    #define ROF(i,a,b) for(int i = a;i >= b;--i)
    #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
    // f[i][j] i 时刻 期望多少个=j 的数字
    // f[i][j] = f[i-1][j] + f[i-1][j-1]/n - f[i-1][j]/n
    const int ha = 1000000007;
    
    inline int qpow(int a,int n=ha-2){
    	int res = 1;
    	while(n){
    		if(n & 1) res = 1ll*res*a%ha;
    		a = 1ll*a*a%ha;
    		n >>= 1;
    	}
    	return res;
    }
    int A[2000005];
    int a[512],b[512],res[512],t[512];
    class ModCounters {
        std::vector<int> S;
        inline void mul(int c[],int a[],int b[]){
            FOR(i,0,511){
                FOR(j,0,511){
                    (c[(i+j)%512] += 1ll*a[i]*b[j]%ha)%=ha;
                }
            }
        }
    
        public:
        int findExpectedSum(std::vector<int> P, int A0, int X, int Y, int N, int K) {
            A[0] = A0;FOR(i,1,N-1) A[i] = (1ll*A[i-1]*X%1812447359+Y)%1812447359;
            S = P;S.resize(N);FOR(i,P.size(),N-1) S[i] = A[i]%512;
            FOR(i,0,N-1) b[S[i]]++;
            a[0] = 1ll*(N-1)*qpow(N)%ha;a[511] = qpow(N);res[0] = 1;
            while(K){
                if(K & 1){
                    mul(t,res,a);
                    FOR(i,0,511) res[i] = t[i],t[i] = 0;
                }
                mul(t,a,a);FOR(i,0,511) a[i] = t[i],t[i] = 0;
                K >>= 1;
            }
            LL ans = 0;
            FOR(i,0,511){
                LL t = 0;
                FOR(k,0,511){
                    (t += 1ll*res[(k-i+512)%512]*b[k]%ha)%=ha;
                }
                (ans += 1ll*t*i%ha)%=ha;
            }
            return ans;
        }
    };
    

    1000pts

    首先可以用两个 ( ext{multiset}) 支持插入删除询问绝对值最小值。一个维护值 一个维护值域上相邻的两个数的差即可。

    暴力是对于每个点 插入它的孙子,爷爷和兄弟。一个菊花图就没了。

    我们针对菊花图考虑去枚举父亲 (p) 每次先把所有儿子和自己的父亲插入。然后对于每一个儿子 (v) 先把 (v) 删除 再插入 (v) 的所有孙子 然后撤销这两步操作。

    发现每个点只会被作为父亲 孙子 被插入(也就是只被插入两次) 总复杂度 (O(nlog n))

    #include<bits/stdc++.h>
    
    #define fi first
    #define se second
    #define U unsigned
    #define P std::pair<int,int>
    #define LL long long
    #define pb push_back
    #define MP std::make_pair
    #define all(x) x.begin(),x.end()
    #define CLR(i,a) memset(i,a,sizeof(i))
    #define FOR(i,a,b) for(int i = a;i <= b;++i)
    #define ROF(i,a,b) for(int i = a;i >= b;--i)
    #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
    
    const int MAXN = 2e5 + 5;
    
    class TwoDistance {
        struct Data_Structure{
            std::multiset<int> S1,S2;
            inline void clear(){
                S1.clear();S2.clear();
            }
        
            inline void insert(int x){
                auto p = S1.insert(x);
                auto pre = p,suf = p;--pre;++suf;
                if(p != S1.begin()) S2.insert(x-*pre);
                if(suf != S1.end()) S2.insert(*suf-x);
                if(p != S1.begin() && suf != S1.end()) S2.erase(S2.find(*suf-*pre));
            }
    
            inline void del(int x){
                auto p = S1.find(x);
                auto pre = p,suf = p;--pre;++suf;
                if(p != S1.begin()) S2.erase(S2.find(x-*pre));
                if(suf != S1.end()) S2.erase(S2.find(*suf-x));
                if(p != S1.begin() && suf != S1.end()) S2.insert(*suf-*pre);
                S1.erase(p);
            }
        
            inline int query(){
                if(S2.empty()) return 0;
                return *S2.begin();
            }
        }DS;
    
        struct Edge{
            int to,nxt;
        }e[MAXN<<1];
        int head[MAXN],cnt;
    
        inline void add(int u,int v){
            e[++cnt] = (Edge){v,head[u]};head[u] = cnt;
            e[++cnt] = (Edge){u,head[v]};head[v] = cnt;
        }
    
        int A[MAXN<<1];LL ans;
        std::vector<int> V,E;
        int f[MAXN];
        std::vector<int> son[MAXN],sson[MAXN];
    
        inline void pdfs(int v,int fa=0){
            f[v] = fa;
            for(int i = head[v];i;i = e[i].nxt){
                if(e[i].to == fa) continue;
                pdfs(e[i].to,v);
            }
        }
    
        inline void dfs(int v,int fa=0){
            DS.clear();
            if(fa) DS.insert(V[fa-1]);
            for(auto x:son[v]) DS.insert(V[x-1]);
            for(int i = head[v];i;i = e[i].nxt){
                if(e[i].to == fa) continue;
                DS.del(V[e[i].to-1]);
                for(auto x:sson[e[i].to]) DS.insert(V[x-1]);
                ans += DS.query();
                DS.insert(V[e[i].to-1]);
                for(auto x:sson[e[i].to]) DS.del(V[x-1]);
            }
            for(int i = head[v];i;i = e[i].nxt){
                if(e[i].to == fa) continue;
                dfs(e[i].to,v);
            }
        }
    
        public:
        long long findMinValue(int N, std::vector<int> edge, std::vector<int> val, int D, int seed) {
            cnt = 0;FOR(i,1,N) head[i] = 0;cnt = 0;
            A[0] = seed;FOR(i,1,2*N-1)  A[i] = (LL)(A[i-1] * 1103515245ll + 12345) % 2147483648;
            V = val;V.resize(N);FOR(i,val.size(),N-1) V[i] = A[i];
            E = edge;E.resize(N);FOR(i,edge.size(),N-1) E[i] = A[N+i]%std::min(i,D);
            FOR(i,1,N-1) add(i+1,E[i]+1);ans = 0;
            pdfs(1);
            FOR(i,1,N){
                if(f[i]) son[f[i]].pb(i);
                if(f[f[i]]) sson[f[f[i]]].pb(i);
            }
            dfs(1);DS.clear();
            for(auto x:sson[1]) DS.insert(V[x-1]);
            ans += DS.query();
            return ans;
        }
    };
    
  • 相关阅读:
    【机器学习】sklearn之生成三类数据用于聚类,python
    【机器学习】sklearn之生成环形和半环型数据,python
    【机器学习】sklearn之创建数据集,python
    【python】使用plotly画三维立体高逼格图,数据可视化
    【python】使用jieba中的textrank提取文本/文章关键词,超简单!
    【python】使用jieba提取文本关键词,超简单!
    【机器学习】gensim.models.Word2Vec()参数的详细解释,python
    XP系统老电脑如何安装Linux系统
    PHP中派生是什么?
    MySQL中CURD是什么?
  • 原文地址:https://www.cnblogs.com/rainair/p/14471599.html
Copyright © 2011-2022 走看看