• 杭电多校第二场


    杭电多校第二场

    1005-Everything Is Generated In Equal Probability[期望递推]

    如果猜的话就是:((n^2-1)/9)

    暴力跑一下得到样例是怎么出来的 然后猜测一下…….

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int mod = 998244353;
    const ll night=443664157;
    int main() {
        ll n;
        while(cin>>n){
            cout<<(n*n%mod-1+mod)%mod*night%mod<<endl;
        }
        return 0;
    }
    

    让我们来探讨一下正解.

    一般做期望的题思路要清晰,要算某个可以算的期望然后获得对答案的贡献.本题最里层的问题就是求逆序对的期望.那每一个点对((x,y)​)都有(frac{1}{2}​)的概率有贡献.易得一个长为(n​)的序列逆序对的期望为(frac {C_{n}^{2}}{2}​)

    一个长为(i)的序列的子序列有(2^i)

    每个子序列的概率为(frac {1}{2^i}​)

    长度为(j)的子序列的个数为(C_{i}^j)

    对本题而言,长度为(i)的长为(i)的子序列期望(f(i)​)等于所有产生的子序列的期望加起来

    [f(i)=frac {1}{2^i}sum_{j=0}^{i}C_{i}^jf(j)+frac {C_{n}^{2}}{2} ]

    左右两边同乘以(2^i)

    [f(i)=frac{1}{2^{i-1}}sum_{j=0}^{i-1}C_{i}^jf(j)+ {C_{n}^{2}}2^{i-1} ]

    就得到一个递推式子 (O(n^2))处理一下

    1008-Harmonious Army[最小割建模]

    可以看一下2016年国家集训队论文“网络流的一些建模方法”

    这题应该从最小割角度建模

    把每条边当做有权边 求最小的边集让S与T不连通

    再用总边权减去最小割

    #include <bits/stdc++.h>
     
    using namespace std;
    const int maxn = 1e5 + 7;
    const int maxm = 1e6 + 7;
    #define ll long long
    const ll inf = 0x3f3f3f3f3f3f3f3f;
    struct Dinic {
        struct Edge {
            int next, to;
            ll f;
        } e[maxm];
        int head[maxn], dep[maxn], tol;
        ll ans;
        int cur[maxn];
        int src, sink, n;
     
        void add(int u, int v, ll f) {
            tol++;
            e[tol].to = v;
            e[tol].next = head[u];
            e[tol].f = f;
            head[u] = tol;
            tol++;
            e[tol].to = u;
            e[tol].next = head[v];
            e[tol].f = 0;
            head[v] = tol;
        }
     
        bool bfs() {
            queue<int> q;
            memset(dep, -1, sizeof(dep));
            q.push(src);
            dep[src] = 0;
            while (!q.empty()) {
                int now = q.front();
                q.pop();
                for (register int i = head[now]; i; i = e[i].next) {
                    if (dep[e[i].to] == -1 && e[i].f) {
                        dep[e[i].to] = dep[now] + 1;
                        if (e[i].to == sink) return true;
                        q.push(e[i].to);
                    }
                }
            }
            return false;
        }
     
        ll dfs(int x, ll maxx) {
            if (x == sink) return maxx;
            for (register int &i = cur[x]; i; i = e[i].next) {
                if (dep[e[i].to] == dep[x] + 1 && e[i].f > 0) {
                    ll flow = dfs(e[i].to, min(maxx, e[i].f));
                    if (flow) {
                        e[i].f -= flow;
                        e[i ^ 1].f += flow;
                        return flow;
                    }
                }
            }
            return 0;
        }
     
        ll dinic(int s, int t) {
            ans = 0;
            this->src = s;
            this->sink = t;
            while (bfs()) {
                for (register int i = 0; i <= n; i++)
                    cur[i] = head[i];
                while (ll d = dfs(src, inf))
                    ans += d;
            }
            return ans;
        }
     
        void init(int n) {
            this->n = n;
            for(int i=0;i<=n;++i) head[i]=0;
            tol = 1;
        }
    } G;
     
    int main() {
        int n,m;
        while(scanf("%d%d",&n,&m)!=EOF){
            ll u,v,a,b,c;
            ll sum=0;
            G.init(n+10);
            int S=0,T=n+2;
            for(int i=1;i<=m;++i){
                scanf("%lld%lld%lld%lld%lld",&u,&v,&a,&b,&c);
                sum+=(a+b+c);
                G.add(S,u,a+b);
                G.add(S,v,a+b);
                G.add(u,T,b+c);
                G.add(v,T,b+c);
                G.add(u,v,a+c-b*2);
                G.add(v,u,a+c-b*2);
            }
            printf("%lld
    ",sum-G.dinic(S,T)/2);
        }
        return 0;
    }
    

    1009-I Love Palindrome String[回文树]

    回文树的模板题

    #include<bits/stdc++.h>
     
    #define ll long long
     
    using namespace std;
    const int MAXN = 300005;
    const int N = 26;
    int ans[MAXN];
     
    struct PAT {
        struct node {
            int len, num, fail, son[N];
        } t[MAXN];
        int x[MAXN];
        short s[MAXN];
        bool vis[MAXN];
        int sum[MAXN];
        int tot, last, n;
     
        void init(int len) {
            for (register int i = 0; i < len + 5; ++i) {
                t[i].len = t[i].num = t[i].fail = 0;
                for (register int j = 0; j < 26; ++j) t[i].son[j] = 0;
                x[i] = vis[i] = 0;
                sum[i] = 0;
            }
            tot = last = 1;
            n = 0;
            t[0].len = 0, t[1].len = -1;
            t[0].fail = t[1].fail = 1;
            s[0] = -1;
        }
     
        void add(int c) {
            int p = last;
            s[++n] = c;
            while (s[n] != s[n - 1 - t[p].len])p = t[p].fail;//匹配找到第一个合法的最长后缀回文子串
            if (!t[p].son[c]) {//如果没有新的本质不同的回文子串
                int v = ++tot, k = t[p].fail;
                while (s[n] != s[n - t[k].len - 1])k = t[k].fail;//获得新节点的fail
                t[v].fail = t[k].son[c];
                t[v].len = t[p].len + 2;
                t[v].num = t[t[v].fail].num + 1;
                t[p].son[c] = v;
            }
            last = t[p].son[c];
            sum[last]++;//不同位置算不同的
        }
     
        void solve() {
            for (register int i = tot; i >= 2; --i) {//从后往前
                if (x[i] == 0) x[i] = i;
                while (x[i] >= 2 && t[x[i]].len > (t[i].len + 1) / 2) {//沿着fail指针找
                    x[i] = t[x[i]].fail;
                }
                if (x[i] >= 2 && t[x[i]].len == (t[i].len + 1) / 2) {//若找到长度为其一半的回文子串的节点
                    vis[i] = 1;//说明这个字符串是满足题意的串
                }
                x[t[i].fail] = x[i];//优化,不需要重复找
                sum[t[i].fail] += sum[i];//父亲累加儿子的sum,因为如果fail[v]=u,则u一定是v的子回文串!
                if (vis[i]) ans[t[i].len] += sum[i];
            }
        }
    } T;
     
    char str[MAXN];
     
    int main() {
        int len;
        ios::sync_with_stdio(false);
        cin.tie(0);
        cout.tie(0);
        while (cin >> str) {
            len = strlen(str);
            T.init(len);
            for (register int i = 1; i <= len; ++i) {
                T.add(str[i-1] - 'a');
                ans[i] = 0;
            }
            T.solve();
            for (register int i = 1; i < len; ++i)cout << ans[i] << " ";
            cout << ans[len] << endl;
        }
        return 0;
    }
     
    

    1010-Just Skip The Problem[签到]

    #include <bits/stdc++.h>
     
    #define ll long long
    using namespace std;
    const int mod = 1e6 + 3;
    ll fac[mod];
     
    int main() {
        fac[0] = 1;
        for (ll i = 1; i < mod; ++i) {
            fac[i] = fac[i - 1] * i % mod;
        }
        int n;
        while (scanf("%d", &n) != EOF) {
            if (n >= mod) {
                puts("0");
            } else {
                printf("%lld
    ", fac[n]);
            }
        }
        return 0;
    }
    

    1011-Keen On Everything But Triangle[主席树+斐波那契数列性质]

    知道正着来只需要44次就能得到三角形

    反着来也要想到

    #include <bits/stdc++.h>
     
    #define ll long long
    using namespace std;
     
    ll a[100005], n, m, copn;
    vector<ll> v;
    struct Node {
        ll l, r, sum;
    } node[100005 * 20];
    ll tot = 0;
    ll tree[100005];
     
    ll getpos(ll x) {
        return lower_bound(v.begin(), v.end(), x) - v.begin() + 1;
    }
     
    ll build(ll l, ll r) {
        ll now = ++tot;
        node[now].sum = 0;
        if (l == r)
            return now;
        ll mid = (l + r) >> 1;
        node[now].l = build(l, mid);
        node[now].r = build(mid + 1, r);
        return now;
    }
     
    ll update(ll last, ll pos) {
        ll now = ++tot, ret = now;
        node[now].sum = node[last].sum + 1;
        ll l = 1, r = n;
        while (l < r) {
            ll mid = (l + r) >> 1;
            if (pos <= mid) {
                node[now].l = ++tot, node[now].r = node[last].r;
                last = node[last].l, now = tot;
                r = mid;
            } else {
                node[now].l = node[last].l, node[now].r = ++tot;
                last = node[last].r, now = tot;
                l = mid + 1;
            }
            node[now].sum = node[last].sum + 1;
        }
        return ret;
    }
     
    /*
    inline void update(ll pre,ll& cur,ll l,ll r,ll v){
        cur=++tot;
        num[cur]=num[pre]+1;
        if(l==r) return;
        ls[cur]=ls[pre],rs[cur]=rs[pre];
        ll m=(l+r)>>1;
        if(v<=m) update(ls[pre],ls[cur],l,m,v);
        else update(rs[pre],rs[cur],m+1,r,v);
    }
    */
     
    ll ask_kth(ll ltree, ll rtree, ll k) {
        ll l = 1, r = n;
        while (l < r) {
            ll mid = (l + r) >> 1;
            if (node[node[rtree].l].sum - node[node[ltree].l].sum >= k) {
                ltree = node[ltree].l, rtree = node[rtree].l;
                r = mid;
            } else {
                k -= (node[node[rtree].l].sum - node[node[ltree].l].sum);
                ltree = node[ltree].r, rtree = node[rtree].r;
                l = mid + 1;
            }
        }
        return l;
    }
     
    void init() {
        v.clear();
        tot = 0;
        for (ll i = 0; i < 100005 * 20; i++)
            node[i].sum = 0;//初始化
        copn = n;
    }
     
    void solve() {
        sort(v.begin(), v.end());
        v.erase(unique(v.begin(), v.end()), v.end());
        n = v.size();//离散化
        tree[0] = build(1, n);
        for (ll i = 1; i <= copn; i++) tree[i] = update(tree[i - 1], getpos(a[i]));
    }
     
    inline ll Query(ll l, ll r, ll cnt) {
        return v[ask_kth(tree[l - 1], tree[r], cnt) - 1];
    }
     
    int main() {
        while (scanf("%lld%lld", &n, &m) != EOF) {
            init();
            for (ll i = 1; i <= n; i++) scanf("%lld", &a[i]), v.push_back(a[i]);
            solve();
            while (m--) {
                ll l, r;
                ll val = -1;
                scanf("%lld%lld", &l, &r);//询问[l,r]第k小
                ll ans1 = 0, ans2 = 0, ans3 = 0;
                for (ll i = 1; i <= (r - l) + 1; i++) {
                    ll cnt = (r - l) + 2 - i;
                    if (ans2) ans1 = ans2;
                    else ans1 = Query(l, r, cnt);
                    cnt--;
                    if (cnt < 1) continue;
     
                    if (ans3) ans2 = ans3;
                    else ans2 = Query(l, r, cnt);
                    cnt--;
                    if (cnt < 1) continue;
     
                    ans3 = Query(l, r, cnt);
                    if (ans1 < ans2 + ans3) {
                        val = ans1 + ans2 + ans3;
                        break;
                    }
                }
                printf("%lld
    ", val);
            }
        }
        return 0;
    }
    
    不要忘记努力,不要辜负自己 欢迎指正 QQ:1468580561
  • 相关阅读:
    Insert Buffering
    B-Tree vs LSM-tree
    MySQL 5.6 死锁演示 及 日志分析
    MySQL索引
    InnoDB的三个关键特性
    MySQL如何优化GROUP BY :松散索引扫描 VS 紧凑索引扫描
    MySql 自适应哈希索引
    母牛的故事
    简单的java程序
    一些变量的比较
  • 原文地址:https://www.cnblogs.com/smallocean/p/11262432.html
Copyright © 2020-2023  润新知