zoukankan      html  css  js  c++  java
  • 2020各省省选试题选做及简要题解

    联考B卷

    Day1T1卡牌游戏

    把前缀和中正的加起来即可,复杂度为(O(N))(难道这题都不会的能去sx?)

    //μ's forever
    #include <bits/stdc++.h>
    #define N 100005
    #define ll long long
    #define getchar nc
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register ll x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    int n,a[N];
    ll sum[N],ans;
    int main()
    {
        n=read();
        for(register int i=1;i<=n;++i)
            a[i]=read(),sum[i]=0ll+sum[i-1]+a[i];
        for(register int i=2;i<=n;++i)
            if(sum[i]>0)
                ans+=sum[i];
        write(ans);
    	return 0;
    }
    

    Day1T2消息传递

    比较裸的一个点分治,每次分治记录(p[i])表示到分治中心(重心)距离为(i)的点的个数,对答案的贡献计算也非常simple,所有长度为k-dep[x]的点数减去在同一子树里的,复杂度为(O(Tnlog n))

    //μ's forever
    #include <bits/stdc++.h>
    #define N 100005
    #define getchar nc
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register int x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    struct edge{
        int to,nxt;
    }e[N<<1];
    int head[N],cnt=0;
    inline void add(register int u,register int v)
    {
        e[++cnt]=(edge){v,head[u]};
        head[u]=cnt;
    }
    int T,n,m,ans[N],f[N],rt,siz[N],ms,vis[N],dep[N],sta[N],top=0,st[N],ed[N],p[N];
    vector<pair<int,int> > q[N];
    inline void getrt(register int x,register int fa)
    {
        f[x]=0,siz[x]=1;
        for(register int i=head[x];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(vis[v]||v==fa)
                continue;
            getrt(v,x);
            f[x]=max(f[x],siz[v]);
            siz[x]+=siz[v];
        }
        f[x]=max(f[x],ms-siz[x]);
        if(f[x]<f[rt])
            rt=x;
    }
    inline void dfs(register int x,register int fa)
    {
        sta[++top]=x;
        st[x]=top;
        for(register int i=head[x];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(v==fa||vis[v])
                continue;
            dep[v]=dep[x]+1;
            dfs(v,x);
        }
        ed[x]=top;
    }
    inline void solve(register int x)
    {
        vis[x]=1,dep[x]=0;
        dfs(x,0);
        for(register int i=1;i<=top;++i)
            ++p[dep[sta[i]]];
        for(register int i=0;i<q[x].size();++i)
            ans[q[x][i].second]+=p[q[x][i].first];
        for(register int i=head[x];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(vis[v])
                continue;
            for(register int j=st[v];j<=ed[v];++j)
                --p[dep[sta[j]]];
            for(register int j=st[v];j<=ed[v];++j)
                for(register int k=0;k<q[sta[j]].size();++k)
                    if(q[sta[j]][k].first>=dep[sta[j]])
                        ans[q[sta[j]][k].second]+=p[q[sta[j]][k].first-dep[sta[j]]];
            for(register int j=st[v];j<=ed[v];++j)
                ++p[dep[sta[j]]];
        }
        while(top)
            --p[dep[sta[top--]]];
        for(register int i=head[x];i;i=e[i].nxt)
        {
            int v=e[i].to;
            if(vis[v])
                continue;
            rt=0;
            ms=siz[v];
            getrt(v,0);
            solve(rt);
        }
    }
    int main()
    {
        T=read();
        while(T--)
        {
            memset(head,0,sizeof(head));
            memset(ans,0,sizeof(ans));
            memset(vis,0,sizeof(vis));
            memset(ans,0,sizeof(ans));
            cnt=0;
            n=read(),m=read();
            for(register int i=1;i<n;++i)
            {
                int u=read(),v=read();
                add(u,v),add(v,u);
            }
            for(register int i=1;i<=m;++i)
            {
                int x=read(),k=read();
                q[x].push_back(make_pair(k,i));
            }
            rt=0;
            f[rt]=ms=n;
            getrt(1,0);
            solve(rt);
            for(register int i=1;i<=m;++i)
                write(ans[i]),puts("");
            for(register int i=1;i<=n;++i)
                q[i].clear();
        }
    	return 0;
    }
    

    Day1T3冰火战士

    发现随着温度的升高,可用冰战士能量之和不降,可用火战士能量之和不升

    题目要求的是两者中较小值的两倍,那么显然两函数交点最优

    求交点不难想到做差,然后再数据结构上查零点(此处零点指当(ice<fire/ice>fire)时,(fire-ice/ice-fire)最小值的点)

    普通的二分零点再判断的算法是(O(n log^2 n))的,并不能通过此题

    这里应该通过倍增的手法来找到这个零点,从0的位置开始,每次加(2^n,2^{n-1},……,2^0),加上的正好就是新值的(lowbit),这样可以(O(1))更新差值并判断

    这样就能在(O(nlog n))时间内解决本题

    //μ's forever
    #include <bits/stdc++.h>
    #define N 2000005
    #define getchar nc
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register int x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    struct bit{
        int ic[N],fr[N],sz,del=0;
        inline void modifyic(register int x,register int val)
        {
            for(register int i=x;i<=sz;i+=(i&(-i)))
                ic[i]+=val;
        }
        inline void modifyfr(register int x,register int val)
        {
            del+=val;
            for(register int i=x+1;i<=sz;i+=(i&(-i)))
                fr[i]-=val;
        }
        inline int qrym(register int x)
        {
            int sic=0,sfr=del;
            for(register int i=x;i;i-=(i&(-i)))
                sic+=ic[i],sfr+=fr[i];
            return min(sic,sfr);
        }
        inline int fd1()
        {
            int res=0,dis=-del;
            for(register int i=20;i>=0;--i)
            {
                if(res+(1<<i)>sz)
                    continue;
                int tmp=dis+ic[res+(1<<i)]-fr[res+(1<<i)];
                if(tmp<0)
                {
                    dis=tmp;
                    res+=(1<<i);
                }
            }
            return res;
        }
        inline int fd2(register int exp)
        {
            int res=0,sic=0,sfr=del;
            for(register int i=20;i>=0;--i)
            {
                if(res+(1<<i)>sz)
                    continue;
                int tmp1=sic+ic[res+(1<<i)],tmp2=sfr+fr[res+(1<<i)];
                if(tmp1<tmp2)
                {
                    res+=(1<<i);
                    sic=tmp1,sfr=tmp2;
                }
                else if(min(tmp1,tmp2)==exp)
                {
                    res=res+(1<<i);
                    sic=tmp1,sfr=tmp2;
                }
            }
            return res;
        }
    }tr;
    struct node{
        int ty,tp,en;
    }q[N];
    int Q,val[N],cnt=0;
    int main()
    {
        Q=read();
        for(register int i=1;i<=Q;++i)
        {
            int x=read();
            if(x==1)
            {
                q[i].ty=read(),q[i].tp=read(),q[i].en=read();
                val[++cnt]=q[i].tp;
            }
            else
            {
                int k=read();
                q[i].ty=q[k].ty,q[i].tp=q[k].tp,q[i].en=-q[k].en;
            }
        }
        sort(val+1,val+cnt+1);
        int ns=unique(val+1,val+cnt+1)-val-1;
        tr.sz=ns;
        for(register int i=1;i<=Q;++i)
            q[i].tp=lower_bound(val+1,val+ns+1,q[i].tp)-val;
        for(register int i=1;i<=Q;++i)
        {
            if(q[i].ty==0)
                tr.modifyic(q[i].tp,q[i].en);
            else
                tr.modifyfr(q[i].tp,q[i].en);
            pair<int,int> ans;
            int ip1=tr.fd1();
            ans=make_pair(tr.qrym(ip1),ip1);
            if(ip1<ns)
            {
                int exp=tr.qrym(ip1+1);
                if(exp>=ans.first)
                {
                    int ip2=tr.fd2(exp);
                    ans=make_pair(exp,ip2);
                }
            }
            if(ans.first==0)
                puts("Peace");
            else
                write(val[ans.second]),putchar(' '),write(ans.first<<1),puts("");
        }
    	return 0;
    }
    

    Day2T1幸运数字

    离散化后进行差分,在前缀异或和上找答案,时间复杂度为(O(n log n))

    //μ's forever
    #include <bits/stdc++.h>
    #define N 100005
    #define getchar nc
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register int x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    struct node{
        int tp,a,b,c;
    }q[N];
    int n,val[N<<1],cnt,tg[N<<1],ans,cur;
    int main()
    {
        n=read();
        val[++cnt]=-2000000000;
        val[++cnt]=0;
        for(register int i=1;i<=n;++i)
        {
            q[i].tp=read();
            if(q[i].tp==1)
            {
                q[i].a=read(),q[i].b=read(),q[i].c=read();
                val[++cnt]=q[i].a,val[++cnt]=q[i].b+1;
            }
            else
            {
                q[i].a=read(),q[i].b=read();
                val[++cnt]=q[i].a,val[++cnt]=q[i].a+1;
            }
        }
        sort(val+1,val+1+cnt);
        int sz=unique(val+1,val+1+cnt)-val-1;
        for(register int i=1;i<=n;++i)
        {
            if(q[i].tp==1)
            {
                int posa=lower_bound(val+1,val+sz+1,q[i].a)-val,posb=lower_bound(val+1,val+sz+1,q[i].b+1)-val;
                tg[posa]^=q[i].c,tg[posb]^=q[i].c;
            }
            else
            {
                int posa=lower_bound(val+1,val+sz+1,q[i].a)-val,posb=posa+1;
                tg[posa]^=q[i].b,tg[posb]^=q[i].b;
                if(q[i].tp==3)
                    tg[1]^=q[i].b;
            }
        }
        for(register int i=1,tmp=0;i<=sz;++i)
        {
            tmp^=tg[i];
            if(tmp>cur)
            {
                cur=tmp;
                if(val[i]<0)
                    ans=val[i+1]-1;
                else
                    ans=val[i];
            }
            else if(tmp==cur)
            {
                if(val[i]<0)
                    ans=val[i+1]-1;
                else if(val[i]<=fabs(ans))
                    ans=val[i];
            }
        }
        printf("%d %d
    ",cur,ans);
    	return 0;
    }
    

    Day2T2信号传递

    (cnt[i][j])表示从(i)(j)共有几个

    考虑状压dp,设(f[S])表示用了(S)集合里的数,考虑了编号为前(|S|)的信号站

    考虑第(pos=|S|+1)个位置,选用了一个没选过的数(i),经过推柿子,可以得到一下转移

    [f[S|(1<<i)]<-f[S]+pos*sum_{j in s,j<i} (k*cnt[i][j]+cnt[j][i])+pos*sum_{j in s, j>i}{-cnt[i][j]+k*cnt[j][i]} ]

    这是个(O(2^m m^2))的暴力,考虑优化

    我们发现后面这一大串实际珂以预处理,又其他状态快速转移得来,得到一个(O(2^m m))的做法,可惜这样会MLE

    这里dyls教了我一个手法,用队列来滚动优化,这样就得到了(O(2^m m))的正解

    //μ's forever
    #include <bits/stdc++.h>
    #define N 100005
    #define M 23
    #define getchar nc
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register int x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    struct node{
        int sta,v[M];
    };
    queue<node> q;
    int n,m,k,s[N],cnt[M][M];
    int bitc[1<<M],id[1<<M],f[1<<M];
    int main()
    {
        n=read(),m=read(),k=read();
        for(register int i=1;i<=n;++i)
            s[i]=read()-1;
        for(register int i=1;i<n;++i)
            ++cnt[s[i]][s[i+1]];
        int Ms=(1<<m)-1;
        for(register int i=0;i<m;++i)
            id[1<<i]=i;
        for(register int i=1;i<=Ms;++i)
            bitc[i]=bitc[i>>1]+(i&1),f[i]=1145141919;
        node tmp;
        tmp.sta=0;
        for(register int i=0;i<m;++i)
        {
            tmp.v[i]=0;
            for(register int j=0;j<m;++j)
                if(j!=i)
                    tmp.v[i]+=k*cnt[j][i]-cnt[i][j];
        }
        q.push(tmp);
        while(!q.empty())
        {
            node a=q.front();
            q.pop();
            int nxtbitc=bitc[a.sta]+1;
            for(register int i=a.sta^Ms;i;i-=i&(-i))
            {
                int nf=f[a.sta],nsta=a.sta|(i&(-i));
                nf+=nxtbitc*a.v[id[i&(-i)]];
                f[nsta]=min(f[nsta],nf);
            }
            for(register int i=0;i<m;++i)
            {
                if((a.sta>>i)&1)
                    break;
                node nsta;
                nsta.sta=a.sta|(1<<i);
                for(register int j=nsta.sta^Ms;j;j-=j&(-j))
                    nsta.v[id[j&(-j)]]=a.v[id[j&(-j)]]+k*cnt[id[j&(-j)]][i]+cnt[i][id[j&(-j)]]-k*cnt[i][id[j&(-j)]]+cnt[id[j&(-j)]][i];
                q.push(nsta);
            }
        }
        printf("%d
    ",f[Ms]);
    	return 0;
    }
    

    Day2T3丁香之路

    考虑每次走的路线,应该是必走的边和自己添加的一些边的"欧拉路",起点和终点为奇点,其他点为偶点(先这样理解,此处欧拉路只是个广义的理解,不是真正的欧拉路)

    程序中把起点和终点度数加一,再按顺序匹配相邻的奇点,给答案加上这条边,这样就结束了?

    还没完,这个图只是定义上满足欧拉路,但不保证连通。用并查集维护连通块,之前连接的两奇点与之间偶点能合并成一个连通块。我们对有的连通块之间求距离,找出最小生成树,给答案加上边权和的两倍,显然这里能成为最小生成树的边是编号相邻两点间的

    这样我们就在(O((m+n^2) log n))的时间内解决了问题

    //μ's forever
    #include <bits/stdc++.h>
    #define ll long long
    #define N 2505
    #define getchar nc
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register ll x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    int n,m,s,fa[N],in[N];
    vector<int> v[N];
    inline int find(register int x)
    {
        return x==fa[x]?x:fa[x]=find(fa[x]);
    }
    struct node{
        int u,v,w;
        bool operator < (const node &a) const{
            return w<a.w;
        }
    };
    int main()
    {
        n=read(),m=read(),s=read();
        ll sum=0;
        for(register int i=1;i<=n;++i)
            fa[i]=i;
        for(register int i=1;i<=m;++i)
        {
            int s=read(),t=read();
            v[s].push_back(t),v[t].push_back(s);
            sum+=fabs(s-t);
            fa[find(s)]=find(t);
        }
        for(register int i=1;i<=n;++i)
            in[i]=find(i);
        for(register int i=1;i<=n;++i)
        {
            for(register int j=1;j<=n;++j)
                fa[j]=j;
            v[s].push_back(i),v[i].push_back(s);
            int pre=0;ll ans=sum;
            for(register int j=1;j<=n;++j)
                if(v[j].size()&1)
                {
                    if(pre)
                    {
                        ans+=j-pre;
                        for(register int k=pre;k<j;++k)
                            fa[find(in[k])]=find(in[j]);
                        pre=0;
                    }
                    else
                        pre=j;
                }
            vector<node> e;
            for(register int j=1;j<=n;++j)
                if(v[j].size())
                {
                    if(pre&&find(in[j])!=find(in[pre]))
                        e.push_back((node){in[j],in[pre],j-pre});
                    else
                        pre=j;
                }
            sort(e.begin(),e.end());
            for(register int j=0;j<e.size();++j)
                if(find(e[j].u)!=find(e[j].v))
                    fa[find(e[j].u)]=e[j].v,ans+=2*e[j].w;
            write(ans),putchar(' ');
            v[s].pop_back(),v[i].pop_back();
        }
        return 0;
    }
    
  • 相关阅读:
    CentOS/RHEL 查看用户登陆信息
    PAM
    块存储
    ECS
    SQL 基础应用
    MySQL 基础管理
    MySQL 体系结构
    JSON对象
    设置dom节点属性的代码优化
    Ext框架下的元素拖动
  • 原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/13199490.html
Copyright © 2011-2022 走看看