zoukankan      html  css  js  c++  java
  • 「模拟赛40」题解

    我好篛啊

    T1:进化

    沙雕题,(没人发现我写的是错解)

    一开始看错题耗了一个多小时导致T4暴力打挂

    考虑每个答案:

    0 0:有连续的1,或有其他字符,或t的个数大于l的个数+1

    1 1:无连续的1且首字母是l

    0 1:无连续的1且首字母是t

    1 0:正经人都知道没有这情况

    T2:皇室战争

    沙雕题,考场写了两个小时的(O(n^2)),大样例一直不过,直接转(O(n^3))

    定义状态 (f_{i,j}) 表示 (i,j) 内是否内消完

    [f_{i,j} | =f_{i,k} 与 f_{k+1,j} ]

    枚举 (k)(O(n^3)),实际上 (f_{i,j}) 只会从 (f_{i+2,j}),(f_{i+1,j-1}),(f_{i,j-2}) 转移

    定义 (g_{i}) 表示以 (i) 为结尾的答案最大值,然后就是常见的分组DP了

    [g_i=g_{i-1} ]

    [g_i=max(g_j+sum_i-sum_j)(f_{i,j}==1) ]

    T3:MC

    考场调到最后发现所有map的insert不能合并两个map,然后就无了

    正解就是经典的时光倒流,合并两个桶

    线段树合并 或 启发式合并+map

    #include<bits/stdc++.h>
    #define Max(a,b) (a>b?a:b)
    #define Min(a,b) (a<b?a:b)
    #define rint register int 
    #define ll long long 
    using namespace std;
    const int maxn=1e6+5,INF=0x3f3f3f3f,mol=19260817;
    inline int read(){
        int s=0,w=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
        return s*w;
    }
    int n,m,k,f[maxn],tot,ans[maxn],dcol,black[maxn],summm,summ,cnt[maxn],siz[maxn];
    ll c[maxn*2],ny[maxn*2];
    unordered_map<int,int> sum[maxn];
    unordered_map<int,int>::iterator it;
    struct Edge{
        int from,to;
    }e[maxn];
    struct Query{
        int opt,id,x,y,z;
        bool operator < (const Query &A)const{
            return id>A.id;
        }
    }q[maxn];
    inline ll qpow(ll _,ll __,ll ___=1){
        while(__){
            if(__&1)___=___*_%mol;
            _=_*_%mol;
            __>>=1;
        }
        return ___;
    }
    void Init(){
        c[0]=1;
        int maxe=1e6;
        for(rint i=1;i<=n;++i)f[i]=i,siz[i]=1;
        for(rint i=1;i<=maxe;++i)c[i]=c[i-1]*i%mol;
        ny[maxe]=qpow(c[maxe],mol-2);
        for(rint i=maxe-1;i>=0;i--)ny[i]=ny[i+1]*(i+1)%mol;
    }
    inline ll C(rint _,rint __){
        if(!__)return 1;
        return c[_]*ny[__]%mol*ny[_-__]%mol;
    }
    inline int Find(rint x){
        while(f[x]!=x)x=f[x];
        return x;
    }
    inline void Merge(rint u,rint v){
        u=Find(u);v=Find(v);
        if(u==v)return;
        if(siz[u]>siz[v]){
            f[v]=u;
            cnt[u]+=cnt[v];
            siz[u]+=siz[v];
            for(it=sum[v].begin();it!=sum[v].end();it++)sum[u][(*it).first]+=(*it).second;
        }else{
            f[u]=v;
            cnt[v]+=cnt[u];
            siz[v]+=siz[u];
            for(it=sum[u].begin();it!=sum[u].end();it++)sum[v][(*it).first]+=(*it).second;
        }
    }
    signed main(){
        freopen("mc.in","r",stdin);
        freopen("mc.out","w",stdout);
        n=read(),m=read(),k=read();Init();
        for(rint i=1,x,y;i<=n;++i)x=read(),y=read(),sum[i][y]=cnt[i]=x;
        for(rint i=1,x,y;i<=m;++i)e[i].from=read(),e[i].to=read();
        for(rint i=1,opt,x,y,z;i<=k;++i){
            opt=read();q[i].opt=opt;q[i].id=i;
            if(opt==1){
                x=read(),y=read(),z=read();
                cnt[x]+=y;sum[x][z]+=y;
                q[i].x=x,q[i].y=y,q[i].z=z;
            }else if(opt==2){
                x=read();black[x]++;
                q[i].x=x;
            }else{
                x=read(),y=read(),z=read();summ=summm=0;q[i].x=x,q[i].y=y,q[i].z=z;
            }
        }
        sort(q+1,q+1+k);
        for(rint i=1;i<=m;++i){
            if(black[i])continue;
            Merge(e[i].from,e[i].to);
        }
        for(rint i=1;i<=k;++i){
            int opt=q[i].opt,x=q[i].x,y=q[i].y,z=q[i].z;
            if(opt==1){
                int rt=Find(x);
                cnt[rt]-=y;sum[rt][z]-=y;
            }else if(opt==2){
                if(--black[x]==0)Merge(e[x].from,e[x].to);
            }else{
                int rt=Find(x);
                summ=sum[rt][z],summm=cnt[rt],tot++;
                if(summ>=y)ans[tot]=C(summ,y)*qpow(C(summm,y),mol-2)%mol;
            }
        }
        for(rint i=tot;i>=1;--i)printf("%d
    ",ans[i]);
        return 0;
    }
    

    T4:简单题

    考场用仅剩的几分钟推出了错误的结论,成功暴零(为啥不给样例解释)

    容易发现 (E(u,v)) 的答案是无视这条边,跑最小生成树,两个点被合并时的边权

    直接做是 (O(n^mlog(m)))

    考虑树边和非树边对答案的影响

    非树边的答案是最小生成树上两点间的最大值

    树边的答案是 (u)(v) 所有非树边的最小值

    都可以写树刨,注意由于边化点的边界问题

    
    
    #include<bits/stdc++.h>
    #define Max(a,b) (a>b?a:b)
    #define Min(a,b) (a<b?a:b)
    #define rint register int 
    #define ll long long 
    using namespace std;
    const int maxn=1e6+5,INF=1e9;
    inline int read(){
    	int s=0,w=1;
    	char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
    	return s*w;
    }
    int n,m,k,f[maxn],tot,head[maxn],dfn[maxn],dclock,par[maxn],depth[maxn],rhead[maxn],tott,top[maxn],siz[maxn],son[maxn],a[maxn],b[maxn],black[maxn];
    ll dis[maxn],ans[maxn];
    struct Edge{
    	int next,from,to,id;
    	ll dis;
    	bool operator <(const Edge &A)const{
    		return dis<A.dis;
    	}
    }e[maxn],re[maxn];
    inline void Add(rint x,rint y,register ll z){e[++tot]=(Edge){head[x],x,y,tot,z};head[x]=tot;}
    inline void rAdd(rint x,rint y,register ll z){re[++tott]=(Edge){rhead[x],x,y,tott,z};rhead[x]=tott;}
    void Init(){
    	for(rint i=1;i<=n;++i)f[i]=i;
    }
    int Find(int x){
    	if(f[x]==x)return x;
    	return f[x]=Find(f[x]);
    }
    void DFS1(int u,int fa){
    	par[u]=fa;siz[u]=1;
    	for(int x=rhead[u];x;x=re[x].next){
    		int v=re[x].to;
    		if(v==fa)continue;
    		depth[v]=depth[u]+1;dis[v]=dis[u]+re[x].dis;
    		a[v]=re[x].dis;
    		DFS1(v,u);
    		siz[u]+=siz[v];
    		if(siz[son[u]]<siz[v])son[u]=v;
    	}
    }
    void DFS2(int u,int t){
    	top[u]=t;dfn[u]=++dclock;b[dfn[u]]=a[u];
    	if(son[u])DFS2(son[u],t);
    	for(int x=rhead[u];x;x=re[x].next){
    		int v=re[x].to;
    		if(v==par[u]||v==son[u])continue;
    		DFS2(v,v);
    	}
    }
    struct Segment_Tree{
    	int l,r,minn,maxx,lazy,siz;
    }tree[maxn*4];
    #define mid ((l+r)>>1)
    void pushup1(int rt){tree[rt].minn=Min(tree[rt*2].minn,tree[rt*2+1].minn);}
    void pushup2(int rt){tree[rt].maxx=Max(tree[rt*2].maxx,tree[rt*2+1].maxx);}
    void Build(int rt,int l,int r){
    	tree[rt].l=l,tree[rt].r=r,tree[rt].siz=r-l+1,tree[rt].maxx=0,tree[rt].minn=INF;
    	if(l==r)return tree[rt].maxx=b[l],void();
    	Build(rt*2,l,mid);Build(rt*2+1,mid+1,r);
    	pushup2(rt);	
    }
    void update(int rt,int w){
    	if(tree[rt].minn>w)tree[rt].minn=w;
    	if(tree[rt].lazy>w||!tree[rt].lazy)tree[rt].lazy=w;
    }
    void pushdown(int rt){
    	if(tree[rt].lazy)update(rt*2,tree[rt].lazy),update(rt*2+1,tree[rt].lazy),tree[rt].lazy=0;
    }
    void modify(int rt,int s,int t,int w){
    	int l=tree[rt].l,r=tree[rt].r;
    	if(s<=l&&r<=t)return update(rt,w),void();
    	pushdown(rt);
    	if(s<=mid)modify(rt*2,s,t,w);
    	if(mid<t)modify(rt*2+1,s,t,w);
    	pushup1(rt);
    }
    int query1(int rt,int s,int t){
    	int l=tree[rt].l,r=tree[rt].r,now=INF;
    	if(s<=l&&r<=t)return tree[rt].minn;
    	pushdown(rt);
    	if(s<=mid)now=min(now,query1(rt*2,s,t));
    	if(mid<t)now=min(now,query1(rt*2+1,s,t));
    	return now;
    }
    int query2(int rt,int s,int t){
    	int l=tree[rt].l,r=tree[rt].r,now=0;
    	if(s<=l&&r<=t)return tree[rt].maxx;
    	pushdown(rt);
    	if(s<=mid)now=max(now,query2(rt*2,s,t));
    	if(mid<t)now=max(now,query2(rt*2+1,s,t));
    	return now;
    }
    void modifymin(int u,int v,int w){
    	while(top[u]!=top[v]){
    		if(dfn[top[u]]>dfn[top[v]])modify(1,dfn[top[u]],dfn[u],w),u=par[top[u]];
    		else modify(1,dfn[top[v]],dfn[v],w),v=par[top[v]];
    	}
    	if(dfn[v]>dfn[u])modify(1,dfn[u]+1,dfn[v],w);
    	else modify(1,dfn[v]+1,dfn[u],w);
    }
    int querymax(int u,int v,int now=0){
    	while(top[u]!=top[v]){
    		if(dfn[top[u]]>dfn[top[v]])now=max(now,query2(1,dfn[top[u]],dfn[u])),u=par[top[u]];
    		else now=max(now,query2(1,dfn[top[v]],dfn[v])),v=par[top[v]];
    	}
    	if(dfn[v]>dfn[u])now=max(now,query2(1,dfn[u]+1,dfn[v]));
    	else now=max(now,query2(1,dfn[v]+1,dfn[u]));
    	return now;
    }
    int querymin(int u,int v,int now=INF){
    	while(top[u]!=top[v]){
    		if(dfn[top[u]]>dfn[top[v]])now=min(now,query1(1,dfn[top[u]],dfn[u])),u=par[top[u]];
    		else now=min(now,query1(1,dfn[top[v]],dfn[v])),v=par[top[v]];
    	}
    	if(dfn[v]>dfn[u])now=min(now,query1(1,dfn[u]+1,dfn[v]));
    	else now=min(now,query1(1,dfn[v]+1,dfn[u]));
    	return now;
    }
    int main(){
    	freopen("easy.in","r",stdin);
    	freopen("easy.out","w",stdout);
    	n=read(),m=read();Init();
    	for(rint i=1,x,y,z;i<=m;++i)x=read(),y=read(),z=read(),Add(x,y,z);
    	sort(e+1,e+1+tot);
    	for(rint i=1;i<=tot;i++){
    		int u=e[i].from,v=e[i].to,rt1=Find(u),rt2=Find(v);
    		if(rt1!=rt2)rAdd(u,v,e[i].dis),rAdd(v,u,e[i].dis),f[rt2]=rt1,black[i]=1;
    	}
    	DFS1(1,1);DFS2(1,0);Build(1,1,n);
    	for(rint i=1;i<=tot;i++){
    		if(!black[i])modifymin(e[i].from,e[i].to,e[i].dis);
    	}
    	for(rint i=1;i<=tot;i++){
    		if(!black[i])ans[e[i].id]=querymax(e[i].from,e[i].to);
    		else ans[e[i].id]=querymin(e[i].from,e[i].to);
    	}
    	for(rint i=1;i<=tot;i++)printf("%lld
    ",ans[i]);
    	return 0;
    }
    
    
  • 相关阅读:
    python类型转换
    手机抓包
    java容器collection的一些简单特点
    WIN7 如何将BAT文件附加到任务栏
    Android新权限机制 AppOps
    记录一写Android常用API
    关于java建立的的包import的问题
    Android组件安全
    查看字节码
    数据库分表之Mybatis+Mysql实践(含部分关键代码)
  • 原文地址:https://www.cnblogs.com/614685877--aakennes/p/14044702.html
Copyright © 2011-2022 走看看