• HGOI 20190407 Typing Competition Round #1 出题记


    /*
          ljc20020730出的HGOI20190407的模拟赛。
          考试结果比预期难的不少,可能是由于本来计划5h的比赛打了4h吧。
          就当普及组模拟赛好了...
          难度大概4紫吧(弱省省选难度)
          出境 小F 命题ljc20020730         
    */

     Task 1 Travel 评测地址

    Task 2 Language 评测地址

    Task 3 Lemon-Tree 评测地址

    Task 4 Future 评测地址

    杭高互测比赛,这次轮到我出题。

    题目是Typing Competition Round #1

    出题人是ljc20020730(捂脸)

    这是第一次出题,就出了一些毒瘤题目,下次一定会改进的2333!!!

    (虽说Task2会有一点点小锅...,但比起某Task3都没STD的模拟赛来说还是良心了不少)

    下面将以出题人的角度评析这场比赛,如果有不足还请dalao多多指教。

    题目概括:

    求树上每个点的最长链$D_i$,m组询问,对于连续区间$[l,r]subseteq [1,n]$

     需满足$Max_{i=l}^{r} D_i - Max_{i=l}^{r} D_i leq Q$

     最大化$r-l+1$的值。

    Sol : 事实上,这道题目出在Task1并不合适,并不小清新。

    首先需要特判第一个点,就是没有乡村的时候特判输出0否则会输出1 

    其次,对于$ O(n) $求全局最长链可以做Dp,设f[u][0]为子树最长链,f[u][1]为子树次长链

    设f[u][2]为从父亲转移过来的最长链,考虑儿子更新父亲(显然f[u][0],f[u][1]可以dfs求出)

    $ f[u][2]=Dist{u,v}+Max(f[u][1],f[u][2])  $[v 是 u最长链经过的点]

    $ f[u][2]=Dist{u,v}+Max(f[u][0],f[u][2])$ [v 非 u最长链经过的点]

    然后对于每个点$D_i = Max(f[i][2],f[i][0])$ 即可

    对于部分链的点貌似需要手打栈,其实只需要把根换成$frac{n}{2}$即可通过

    通过计算时间复杂度发现对于区间Max值需要O(1)(由于有nm次询问) 所以打了ST表维护就行

    使用类似于单调队列的方法可以做到询问复杂度$O(nm)$

    总时间复杂度为$O(n +n log_2 n + nm)$,足以通过所有数据。

    # include <cstring>
    # include <cstdio>
    # include <cmath>
    # define fp(i,s,t) for(int i=s;i<=t;i++)
    using namespace std;
    const int N=50000+10;
    const int Bit=16;
    struct rec{
        int pre,to,w;
    }a[N<<1];
    int cmin[N][17],cmax[N][17],mark[N],g[N],f[N][3],lg2[N];
    bool vis[N];
    int tot,head[N];
    int n,m,root;
    inline int max(int a,int b){return (a>b)?a:b;}
    inline int min(int a,int b){return (a>b)?b:a;}
    inline int read()
    {
        int X=0,w=0; char c=0;
        while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
        while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
        return w?-X:X;
    }
    inline void write(int x)
    {
        if (x>9) write(x/10);
        putchar('0'+x%10);
    }
    inline void adde(int u,int v,int w)
    {
        a[++tot].pre=head[u];
        a[tot].to=v;
        a[tot].w=w;
        head[u]=tot;
    }
    void dfs1(int u)
    {
        vis[u]=1;
        for (int i=head[u];i;i=a[i].pre){
            int v=a[i].to; if (vis[v]) continue;
            dfs1(v);
            if (f[v][0]+a[i].w>f[u][0]) {
                mark[u]=v;
                f[u][1]=f[u][0];
                f[u][0]=f[v][0]+a[i].w;
            } else if (f[v][0]+a[i].w>f[u][1]) {
                f[u][1]=f[v][0]+a[i].w;
            }
        }
    }
    void dfs2(int u)
    {
        vis[u]=1;
        for (int i=head[u];i;i=a[i].pre){
            int v=a[i].to; if (vis[v]) continue;
            if (mark[u]==v) f[v][2]=a[i].w+max(f[u][2],f[u][1]);
            else f[v][2]=a[i].w+max(f[u][2],f[u][0]);
            dfs2(v);
        }
    }
    void buildRMQ()
    {
        memset(cmin,0x3f,sizeof(cmin));
        for (int i=1;i<=n;i++) cmax[i][0]=cmin[i][0]=g[i];
        for (int i=1;(1<<i)<=n;i++) fp(j,1,n)
            cmax[j][i]=max(cmax[j][i-1],cmax[j+(1<<(i-1))][i-1]),
            cmin[j][i]=min(cmin[j][i-1],cmin[j+(1<<(i-1))][i-1]);
    }
    int query(int l,int r)
    {
        int k=lg2[r-l+1];
        return max(cmax[l][k],cmax[r-(1<<k)+1][k])-min(cmin[l][k],cmin[r-(1<<k)+1][k]);
    }
    int main()
    {
        freopen("travel.in","r",stdin);
        freopen("travel.out","w",stdout);
        n=read();m=read(); root=n>>1;
        if (n==1) {
            fp(i,1,m) printf("0
    ");
            return 0;
        }
        fp(i,1,n) lg2[i]=log2(i);
        fp(i,1,n-1) {
            int u=read(),v=read(),w=read();
            adde(u,v,w); adde(v,u,w);
        }
        dfs1(root); 
        memset(vis,false,sizeof(vis));
        dfs2(root);
        fp(i,1,n) g[i]=max(f[i][0],f[i][2]);
        buildRMQ();
        while (m--) {
            int q=read(),l=1,ans=0;
            for (int i=1;i<=n;i++) {
                while (l<i&&query(l,i)>q) l++;
                ans=max(i-l+1,ans);
            }
            write(ans); putchar('
    ');
        }
        return 0;
    }
    travel.cpp

    考试时最高分96分原因是没有特判第一个点...

    题目概括:

    对于一个RP++语言要求支持

    for i = p to q 

    a = b + c 
    if a = b then 

    (所有格式严格只会出现$a,b,c$三个字母)

    Sol : 细节题目:只需要模拟就可以过75分。

    事实上我们会发现多数for循环是没有意义的,分三类讨论即可

    1. 赋值 a = b + c套循环

    2.累加 a = a + b 套循环

    3.乘2 a=a+a套循环

    所以可以O(1)处理上面操作。

    而对于if 套for 直接拆成if + for按照上面处理即可

    而对于for 套 if的情况会发现要么处理对if条件没有影响,此时只需要把if 套在for 外面就行 按照上面处理

    要么处理对if条件有影响,但由于a,b,c是大于等于1的所以必然只影响一次,所以直接把for拆掉做if 即可(此处需要判断for 的成立性)

    注意处理for循环的时候的倒序循环不需要做处理就行,复杂度可以做到O(length)

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #define int unsigned long long
    #define ull unsigned long long
    using namespace std;
    struct rec {
        int opt;
        string a1, a2, a3;
    } t[10005];
    ull a, b, c;
    int n;
    string s[10005];
    bool pdc(char x) {
        if (x == 'a' || x == 'b' || x == 'c')
            return 1;
        else
            return 0;
    }
    ull val(char x) {
        if (x == 'a')
            return a;
        else if (x == 'b')
            return b;
        else if (x == 'c')
            return c;
    }
    ull pow(ull x, int n) {
        ull ans = 1;
        while (n) {
            if (n & 1)
                ans = ans * x;
            n >>= 1;
            x = x * x;
        }
        return ans;
    }
    inline void give(char ch1, char ch2, char ch3) {
        if (ch1 == 'a' && ch2 == 'a' && ch3 == 'a')
            a = a + a;
        else if (ch1 == 'a' && ch2 == 'a' && ch3 == 'b')
            a = a + b;
        else if (ch1 == 'a' && ch2 == 'a' && ch3 == 'c')
            a = a + c;
        else if (ch1 == 'a' && ch2 == 'b' && ch3 == 'a')
            a = b + a;
        else if (ch1 == 'a' && ch2 == 'b' && ch3 == 'b')
            a = b + b;
        else if (ch1 == 'a' && ch2 == 'b' && ch3 == 'c')
            a = b + c;
        else if (ch1 == 'a' && ch2 == 'c' && ch3 == 'a')
            a = c + a;
        else if (ch1 == 'a' && ch2 == 'c' && ch3 == 'b')
            a = c + b;
        else if (ch1 == 'a' && ch2 == 'c' && ch3 == 'c')
            a = c + c;
        else if (ch1 == 'b' && ch2 == 'a' && ch3 == 'a')
            b = a + a;
        else if (ch1 == 'b' && ch2 == 'a' && ch3 == 'b')
            b = a + b;
        else if (ch1 == 'b' && ch2 == 'a' && ch3 == 'c')
            b = a + c;
        else if (ch1 == 'b' && ch2 == 'b' && ch3 == 'a')
            b = b + a;
        else if (ch1 == 'b' && ch2 == 'b' && ch3 == 'b')
            b = b + b;
        else if (ch1 == 'b' && ch2 == 'b' && ch3 == 'c')
            b = b + c;
        else if (ch1 == 'b' && ch2 == 'c' && ch3 == 'a')
            b = c + a;
        else if (ch1 == 'b' && ch2 == 'c' && ch3 == 'b')
            b = c + b;
        else if (ch1 == 'b' && ch2 == 'c' && ch3 == 'c')
            b = c + c;
        else if (ch1 == 'c' && ch2 == 'a' && ch3 == 'a')
            c = a + a;
        else if (ch1 == 'c' && ch2 == 'a' && ch3 == 'b')
            c = a + b;
        else if (ch1 == 'c' && ch2 == 'a' && ch3 == 'c')
            c = a + c;
        else if (ch1 == 'c' && ch2 == 'b' && ch3 == 'a')
            c = b + a;
        else if (ch1 == 'c' && ch2 == 'b' && ch3 == 'b')
            c = b + b;
        else if (ch1 == 'c' && ch2 == 'b' && ch3 == 'c')
            c = b + c;
        else if (ch1 == 'c' && ch2 == 'c' && ch3 == 'a')
            c = c + a;
        else if (ch1 == 'c' && ch2 == 'c' && ch3 == 'b')
            c = c + b;
        else if (ch1 == 'c' && ch2 == 'c' && ch3 == 'c')
            c = c + c;
    }
    inline void workf(char ch1, char ch2, int k) {
        if (ch1 == 'a' && ch2 == 'a')
            a = a * pow(2, k);
        else if (ch1 == 'a' && ch2 == 'b')
            a = a + k * b;
        else if (ch1 == 'a' && ch2 == 'c')
            a = a + k * c;
        else if (ch1 == 'b' && ch2 == 'a')
            b = b + k * a;
        else if (ch1 == 'b' && ch2 == 'b')
            b = b * pow(2, k);
        else if (ch1 == 'b' && ch2 == 'c')
            b = b + k * c;
        else if (ch1 == 'c' && ch2 == 'a')
            c = c + k * a;
        else if (ch1 == 'c' && ch2 == 'b')
            c = c + k * b;
        else if (ch1 == 'c' && ch2 == 'c')
            c = c * pow(2, k);
    }
    string aa1;
    bool fun1() {
        string a = aa1;
        int i, len = a.length();
        for (i = 0; i < len; i++)
            if (pdc(a[i]))
                break;
        char c1 = a[i];
        for (i = i + 1; i < len; i++)
            if (pdc(a[i]))
                break;
        char c2 = a[i];
        return val(c1) == val(c2);
    }
    string aa2;
    int fun2() {
        string a = aa2;
        int l = 0, r = 0, i, len = a.length();
        for (i = 0; i < len; i++)
            if (a[i] >= '0' && a[i] <= '9')
                break;
        for (; i < len; i++)
            if (a[i] >= '0' && a[i] <= '9')
                l = (int)l * 10 + a[i] - '0';
            else
                break;
        for (i = i + 1; i < len; i++)
            if (a[i] >= '0' && a[i] <= '9')
                break;
        for (; i < len; i++)
            if (a[i] >= '0' && a[i] <= '9')
                r = (int)r * 10 + a[i] - '0';
            else
                break;
        int zero = 0;
        if (l < r)
            return r - l + 1;
        else
            return 0;
    }
    bool relation() {
        int i, len = aa1.length();
        for (i = 0; i < len; i++)
            if (pdc(aa1[i]))
                break;
        char c1 = aa1[i];
        for (i = i + 1; i < len; i++)
            if (pdc(aa1[i]))
                break;
        char c2 = aa1[i];
        len = aa2.length();
        for (i = 0; i < len; i++)
            if (pdc(aa2[i]))
                break;
        char c3 = aa2[i];
        if (c1 == c3 || c2 == c3)
            return 1;
        else
            return 0;
    }
    void work1(int id) {
        aa1 = t[id].a1;
        if (!fun1())
            return;
        string a = t[id].a2;
        int i, len = a.length();
        for (i = 0; i < len; i++)
            if (pdc(a[i]))
                break;
        char c1 = a[i];
        for (i = i + 1; i < len; i++)
            if (pdc(a[i]))
                break;
        char c2 = a[i];
        for (i = i + 1; i < len; i++)
            if (pdc(a[i]))
                break;
        char c3 = a[i];
        give(c1, c2, c3);
    }
    void work2(int id) {
        aa2 = t[id].a1;
        int times = fun2();
        if (times<=0) return;
        string a = t[id].a2;
        int i, len = a.length();
        for (i = 0; i < len; i++)
            if (pdc(a[i]))
                break;
        char c1 = a[i];
        for (i = i + 1; i < len; i++)
            if (pdc(a[i]))
                break;
        char c2 = a[i];
        for (i = i + 1; i < len; i++)
            if (pdc(a[i]))
                break;
        char c3 = a[i];
        if (c2 == c1)
            workf(c1, c3, times);
        else if (c3 == c1)
            workf(c1, c2, times);
        else
            give(c1, c2, c3);
    }
    void work0(int id) {
        aa1 = t[id].a1;
        if (!fun1())
            return;
        t[id].a1 = t[id].a2;
        t[id].a2 = t[id].a3;
        work2(id);
    }
    void work3(int id) {
        string a = t[id].a1;
        int i, len = a.length();
        for (i = 0; i < len; i++)
            if (pdc(a[i]))
                break;
        char c1 = a[i];
        for (i = i + 1; i < len; i++)
            if (pdc(a[i]))
                break;
        char c2 = a[i];
        for (i = i + 1; i < len; i++)
            if (pdc(a[i]))
                break;
        char c3 = a[i];
        give(c1, c2, c3);
    }
    signed main() {
        cin >> a >> b >> c >> n; 
        getchar();
        for (int i = 1; i <= n; i++) getline(cin, s[i]);
        int i = 1, cnt = 0;
        while (i <= n) {
            if (s[i][0] == 'f') {
                if (pdc(s[i + 1][0])) {
                    aa2=s[i];   if (fun2()<=0) {i+=2; continue; }
                    t[++cnt] = (rec){ 2, s[i], s[i + 1] };
                    i += 2;
                } else {
                    aa2=s[i];   if (fun2()<=0) {    i+=3; continue; }
                    aa1 = s[i + 1];     aa2 = s[i + 2];
                    if (relation()) {
                        t[++cnt] = (rec){ 1, s[i + 1], s[i + 2] };
                    } else {
                        t[++cnt] = (rec){ 0, s[i + 1], s[i], s[i + 2] };
                    }
                    i += 3;
                }
            } else if (s[i][0] == 'i') {
                if (pdc(s[i + 1][0])) {
                    t[++cnt] = (rec){ 1, s[i], s[i + 1] };
                    i += 2;
                } else {
                    aa2=s[i+1]; if (fun2()<=0) {i+=3; continue; }
                    t[++cnt] = (rec){ 0, s[i], s[i + 1], s[i + 2] };
                    i += 3;
                }
            } else {
                t[++cnt] = (rec){ 3, s[i] };
                i++;
            }
        }
        n = cnt;
        for (int i = 1; i <= n; i++) {
            if (t[i].opt == 0)
                work0(i);
            else if (t[i].opt == 1)
                work1(i);
            else if (t[i].opt == 2)
                work2(i);
            else
                work3(i); 
        }
        cout << a << " " << b << " " << c << '
    ';
        return 0;
    }
    language.cpp

    考场上最高分是65分,原因是没有处理好一些细节和for循环的优化。

    考试时应该是最不可做的题目,为了卡一些选手的时间才放的这道题。

    所以遇到毒瘤的模拟题数个0 0 0得分可能比一些选手的分高(心态不能崩!!!)

    Sol:概括题目显然非常不必要,这道题应该能一眼看出来是线段树+树链剖分的题目。

    树链剖分不必多说,考虑线段树维护的信息。

    显然,区间平均值直接维护区间和即可,但是方差并不能直接维护。

    经过推倒我们可以发现

    显然只需要维护一个区间平方和即可,所以当维护一个区间+d的时候

    套树剖以后复杂度是$O(n log_2 ^2 n)$

    # include <bits/stdc++.h>
    # define Eps (1e-7)
    using namespace std;
    const int N=1e5+10;
    struct node{
        int l,r;
        double sum,sqr,add;
    }t[N<<2];
    int n,m;
    inline int read()
    {
        int X=0,w=0; char c=0;
        while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
        while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
        return w?-X:X;
    }
    double val[N],tmp[N];
    struct rec{
        int pre,to;
    }a[N<<1];
    int head[N],tot,cntw,top[N];
    int size[N],fa[N],w[N],old[N],dep[N],son[N];
    void adde(int u,int v)
    {
        a[++tot].pre=head[u];
        a[tot].to=v;
        head[u]=tot;
    }
    # define ls (x<<1)
    # define rs ((x<<1)+1)
    void build(int x,int l,int r)
    {
        t[x].l=l; t[x].r=r;
        if (l==r) {
            t[x].sum=val[l];
            t[x].sqr=val[l]*val[l];
            return;
        }
        int mid=l+r>>1;
        build(ls,l,mid);
        build(rs,mid+1,r);
        t[x].sum=t[ls].sum+t[rs].sum;
        t[x].sqr=t[ls].sqr+t[rs].sqr; 
    }
    void down(int x)
    {
        if (fabs(t[x].add)<=Eps) return;
        double tag=t[x].add; t[x].add=0.0;
        t[ls].sqr=t[ls].sqr+2*tag*t[ls].sum+1.0*(t[ls].r-t[ls].l+1)*tag*tag;
        t[rs].sqr=t[rs].sqr+2*tag*t[rs].sum+1.0*(t[rs].r-t[rs].l+1)*tag*tag;
        t[ls].sum=t[ls].sum+1.0*(t[ls].r-t[ls].l+1)*tag;
        t[rs].sum=t[rs].sum+1.0*(t[rs].r-t[rs].l+1)*tag;
        t[ls].add=t[ls].add+tag;
        t[rs].add=t[rs].add+tag;
    }
    void modify(int x,int pos,double d)
    {
        if (t[x].l==t[x].r) {
            t[x].sum=d;
            t[x].sqr=d*d;
            return;
        }
        down(x);
        int mid=(t[x].l+t[x].r)>>1;
        if (pos<=mid) modify(ls,pos,d);
        else modify(rs,pos,d);
        t[x].sum=t[ls].sum+t[rs].sum;
        t[x].sqr=t[ls].sqr+t[rs].sqr; 
    }
    void update(int x,int opl,int opr,double d)
    {
        if (opl<=t[x].l&&t[x].r<=opr) {
            t[x].sqr=t[x].sqr+2*(t[x].sum)*d+1.0*(t[x].r-t[x].l+1)*d*d;
            t[x].sum=t[x].sum+1.0*(t[x].r-t[x].l+1)*d;
            t[x].add=t[x].add+d;
            return;
        }
        down(x);
        int mid=(t[x].l+t[x].r)>>1;
        if (opl<=mid) update(ls,opl,opr,d);
        if (opr>mid) update(rs,opl,opr,d);
        t[x].sum=t[ls].sum+t[rs].sum;
        t[x].sqr=t[ls].sqr+t[rs].sqr; 
    }
    double query_sum(int x,int opl,int opr)
    {
        if (opl<=t[x].l&&t[x].r<=opr) return t[x].sum;
        down(x);
        int mid=(t[x].l+t[x].r)>>1;
        double ret=0.0;
        if (opl<=mid) ret=ret+query_sum(ls,opl,opr);
        if (opr>mid)  ret=ret+query_sum(rs,opl,opr);
        return ret;
    }
    double query_sqr(int x,int opl,int opr)
    {
        if (opl<=t[x].l&&t[x].r<=opr) return t[x].sqr;
        down(x);
        int mid=(t[x].l+t[x].r)>>1;
        double ret=0.0;
        if (opl<=mid) ret=ret+query_sqr(ls,opl,opr);
        if (opr>mid)  ret=ret+query_sqr(rs,opl,opr);
        return ret;
    }
    void dfs1(int u,int fath,int depth)
    {
        fa[u]=fath;dep[u]=depth;size[u]=1;
        for (int i=head[u];i;i=a[i].pre){
            int v=a[i].to;
            if (v==fath) continue;
            dfs1(v,u,depth+1);
            size[u]+=size[v];
            if (size[son[u]]<size[v]) son[u]=v;
        }
    }
    void dfs2(int u,int tp)
    {
        w[u]=++cntw;top[u]=tp; old[cntw]=u;
        if (son[u]!=0) dfs2(son[u],tp);
        for (int i=head[u];i;i=a[i].pre){
            int v=a[i].to;
            if (v==fa[u]||v==son[u]) continue;
            dfs2(v,v);
        }
    }
    double ans1,ans2;
    void query(int u,int v)
    {
        int f1=top[u],f2=top[v],num=0;
        double ret_sum=0.0,ret_sqr=0.0;
        while (f1!=f2) {
            if (dep[f1]<dep[f2]) swap(f1,f2),swap(u,v);
            num+=(w[u]-w[f1]+1);
            ret_sum=ret_sum+query_sum(1,w[f1],w[u]);
            ret_sqr=ret_sqr+query_sqr(1,w[f1],w[u]);
            u=fa[f1]; f1=top[u];
        }
        if (dep[u]>dep[v]) swap(u,v);
        num+=(w[v]-w[u]+1);
        ret_sum=ret_sum+query_sum(1,w[u],w[v]);
        ret_sqr=ret_sqr+query_sqr(1,w[u],w[v]);
        ans1=ret_sum/(1.0*num);
        ans2=ret_sqr/(1.0*num)-(ans1*ans1);
    }
    signed main()
    {
        freopen("lemontree.in","r",stdin);
        freopen("lemontree.out","w",stdout);
        n=read();
        for (int i=2;i<=n;i++){
            int u=read(),v=read();
            adde(u,v); adde(v,u); 
        } 
        dfs1(1,0,0);
        dfs2(1,0);
        for (int i=1;i<=n;i++) scanf("%lf",&tmp[i]);
        for (int i=1;i<=n;i++) val[i]=tmp[old[i]];
        build(1,1,n);
        int op; double x,y;
        while(~scanf("%d%lf%lf",&op,&x,&y)) {
            int u,v; double d;
            if (op==1) {
                u=(int)x; d=1.0*y;
                modify(1,w[u],d);
            } else if (op==2) {
                u=(int)x; d=(double)y;
                update(1,w[u],w[u]+size[u]-1,d);
            } else if (op==3) {
                u=(int)x; v=(int)y;
                query(u,v);
                printf("%.5lf
    ",ans1);
            } else if (op==4) {
                u=(int)x;v=(int)y;
                if (u==v) { puts("0.000"); continue;}
                query(u,v);
                printf("%.5lf
    ",ans2);
            }
        }
        return 0;
    } 
    lemontree.cpp

    考试时hjc得分最高拿到44分,原因是使用的cin,读入被卡了

    关于cin他已经死了...

    剩下的人全部打了2分的部分分什么情况(dfs都不会了么...)

    题意概括:

    对于第一问50pts询问一个序列的所有子序列bit-and和bit-or 的和各是多少。 

    对于第二问50pts询问n个盒子里装有奖品,m个人等概率随机 选择奖品,选完之后空盒子放回,求奖品剩余数期望。

    Sol:

    第一小问:求按位and连续子序列和 

    对于位运算的题目按位考虑,对于每一位,只有连续为1的区间对 答案产生贡献。 

    假设第k位上某段连续区间长为len,那么贡献值是$ frac{len imes (len+1)}{2} imes 2 ^k $ 累加所有位的贡献即可。 

    第二小问:求按位or连续子序列和

    只有连续为0的区间对答案产生负贡献, 

    假设第k位上某段连续区间长为len,

    那么贡献值是$ −frac{len imes (len+1)}{ 2} imes 2 ^k $

    补集转换即可。 

    总复杂度$ O(n log_2 n) $

    对于第二个问题直接推公式,

    对于每个奖品不被选中的概率是$frac{n-1}{n}$

    所以对于m个人都没选这个奖品的概率是$(frac{n-1}{n})^m$

    所以剩余奖品的期望是$n imes (frac{n-1}{n})^m $

    是在mod p=998244353意义下运算,所以直接求逆元

    $ (n-1)^m imes (n^{-1})^m imes n $

    对于指数部分直接扩展欧拉定理降幂即可,对于大整数求逆部分考虑性质

    若a关于b同余那么a,b必然有相同的逆元。

    证明如下: 设$a equiv  b (mod p)$ 那么必然 $acequiv  bc (mod p)$

    若c是a的逆元那么$ac equiv 1 (mod p )$那么必然$bc equiv 1 (mod p )$

    由逆元的唯一性可证。(事实上可以通过费马小定理求逆元感性理解)

    所以根本不需使用高精度复杂度$O(length + 2 log_2 p)$

    # include <cstdio>
    # include <iostream>
    # define int long long
    using namespace std;
    const int mp=998244353;
    const int N=5e5+10;
    int res1,res2,pw[32]; 
    inline void read(int Mo,int Phi)
    {
        int x=0,X=0,f=0; char c=0;
        while (!(c>='0'&&c<='9')) c=getchar();
        while (c>='0'&&c<='9') {
            x=(x<<1)+(x<<3)+c-'0';if (x>=Phi)f=1; x%=Phi;
            X=(X<<1)+(X<<3)+c-'0';X%=Mo;
            c=getchar();
        }
        res1=X,res2=x+(f==1?Phi:0);
    }
    inline int Read()
    {
        int X=0,w=0; char c=0;
        while(c<'0'||c>'9') {w|=c=='-';c=getchar();}
        while(c>='0'&&c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
        return w?-X:X;
    }
    int a[N],n;
    int workA()
    {
        int ans=0; 
        for (int i=31;~i;i--) {
            int ret=0;
            for (int j=1;j<=n;j++)
             if ((a[j]>>i)&1) ret++;
             else {
                 ans=(ans+ret*(1+ret)/2%mp*pw[i]%mp)%mp;
                 ret=0;
             }
            ans=(ans+ret*(1+ret)/2%mp*pw[i]%mp)%mp; 
        }
        return ans%mp;
    } 
    int workB()
    {
        int ans=0;
        for (int i=31;~i;i--) {
            int ret=0; ans=(ans+n*(1+n)/2%mp*pw[i]%mp)%mp;
            for (int j=1;j<=n;j++)
             if ((a[j]>>i)&1) {
                 ans=((ans%mp-(ret*(1+ret)/2%mp*pw[i]%mp))%mp+mp)%mp;
                 ret=0;
             }else ret++;
            ans=((ans%mp-(ret*(1+ret)/2%mp*pw[i]%mp))%mp+mp)%mp;
        }
        return ans%mp;
    }
    int Pow(int x,int n,int p)
    {
        int ans=1;
        for (;n;n>>=1,x=x*x%p)
         if (n&1) ans=ans*x%p;
        return ans%p; 
    }
    int work2()
    {
        read(mp,mp-1);
        int n0=res1,n1=(n0+mp-1)%mp,inv_n=Pow(n0,mp-2,mp);
        read(mp,mp-1);
        int m=res2;
        int ans=Pow(n1,m,mp)*Pow(inv_n,m,mp)%mp*n0%mp;
        return ans;
    }
    signed main()
    {
        freopen("future.in","r",stdin);
        freopen("future.out","w",stdout);
        n=Read();
        pw[0]=1;
        for (int i=1;i<=31;i++) pw[i]=pw[i-1]*2%mp;
        for (int i=1;i<=n;i++) a[i]=Read();
        cout<<workA()<<' '<<workB()<<'
    '<<work2()<<'
    '; 
        return 0;
    }
    future.cpp

     最后,考场的评测结果大概是长这样子的。。。

    Hjc最巨了!!!

  • 相关阅读:
    Java SE——线程介绍
    Vue
    Spring asm
    spring 自定义标签的实现
    Spring InitializingBean 接口以及Aware接口实现的原理
    值传递与引用传递
    redis学习
    ssm多数据源配置
    redis 启动
    json的设置
  • 原文地址:https://www.cnblogs.com/ljc20020730/p/10667288.html
Copyright © 2020-2023  润新知