• AtCoder Grand Contest 001 题解


    传送门

    (A)

    咕咕咕

    const int N=505;
    int a[N],n,res;
    int main(){
    	scanf("%d",&n);
    	fp(i,1,n<<1)scanf("%d",&a[i]);
    	sort(a+1,a+1+(n<<1));
    	fp(i,1,n)res+=a[(i<<1)-1];
    	printf("%d
    ",res);
    	return 0;
    }
    

    (B)

    考虑递归,记(las)表示画的上一个三角形的边长,(now)为现在的三角形的边长,如果(now|las),则再走(las*2-las)就可以到终点,否则我们可以走(now)的整数倍次,也就是说取个模,然后再计算下一个(las)(now)就行了,复杂度为(O(log n))

    建议画图理解

    ll n,x,res,las,now,t;
    int main(){
    	scanf("%lld%lld",&n,&x);
    	res=n,las=n-x,now=x;
    	while(now){
    		if(las%now==0){res+=(las<<1)-now;break;}
    		res+=(las/now*now)<<1,t=now,now=las%now,las=t;
    	}
    	printf("%lld
    ",res);
    	return 0;
    }
    

    (C)

    (f_{u,i})表示考虑(u)的子树内,且(u)子树内未被删去的点中深度最深的点里(u)的距离为(i),此时子树内剩余的点数最多为多少,转移只用合法的状态转移就是了

    //quming
    #include<bits/stdc++.h>
    #define R register
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
    template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
    using namespace std;
    const int N=2005;
    struct eg{int v,nx;}e[N<<1];int head[N],tot;
    inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
    int f[N][N],g[N],mx[N],n,res,k;
    void dfs(int u,int fa){
    	memset(f[u],0xef,sizeof(f[u]));
    	f[u][0]=1;
    	go(u)if(v!=fa){
    		dfs(v,u),memcpy(g,f[u],(max(mx[u],mx[v]+1)+1)<<2);
    		fp(i,0,mx[u])fp(j,0,mx[v])if(i+j+1<=k)
    			cmax(g[max(i,j+1)],f[u][i]+f[v][j]);
    		cmax(mx[u],mx[v]+1),memcpy(f[u],g,(mx[u]+1)<<2);
    	}
    }
    int main(){
    	scanf("%d%d",&n,&k);
    	for(R int i=1,u,v;i<n;++i)scanf("%d%d",&u,&v),add(u,v),add(v,u);
    	dfs(1,0);
    	fp(i,1,n)fp(j,0,min(mx[i],k))cmax(res,f[i][j]);
    	printf("%d
    ",n-res);
    	return 0;
    }
    

    (D)

    首先如果奇数的个数超过(2)就无解了,具体可以把回文串的相同看做连边,至少得连成一棵生成树,奇数的话中间的点就无法连边了,所以奇数大于(2)(gg)

    否则的话我们把奇数放到两边,并把最两边分别(+1-1),剩下的按顺序来就可以了

    //quming
    #include<bits/stdc++.h>
    #define R register
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
    template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
    using namespace std;
    const int N=1e5+5;
    int st[N],a[N],id[N],tt,n,m,top;
    inline void Ot(){printf("%d
    ",top);fp(i,1,top)printf("%d%c",st[i]," 
    "[i==top]);}
    int main(){
    //	freopen("testdata.in","r",stdin);
    	scanf("%d%d",&n,&m);
    	fp(i,1,m){
    		scanf("%d",&a[i]);
    		if(a[i]&1)id[++tt]=i;
    	}
    	if(tt>2)return puts("Impossible"),0;
    	if(tt>0)swap(a[1],a[id[1]]);if(tt>1)swap(a[m],a[id[2]]);
    	fp(i,1,m)printf("%d%c",a[i]," 
    "[i==m]);
    	if(m==1){
    		st[++top]=1;
    		if(a[1]-1)st[++top]=a[1]-1;
    	}else{
    		--a[1],++a[m];
    		fp(i,1,m)if(a[i])st[++top]=a[i];
    	}
    	return Ot(),0;
    }
    

    (E)

    好吧的确还是比较菜……

    我们把({a_i+b_i+a_j+b_jchoose a_i+a_j})变成从((-a_i,-b_i))走到((a_j,b_j))的方案数,那么可以直接通过(O(MAX^2))(dp)算出(sum_{i=1}^nsum_{j=1}^n{a_i+b_i+a_j+b_jchoose a_i+a_j}),减掉多算的就行了

    //quming
    #include<bits/stdc++.h>
    #define R register
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
    template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
    using namespace std;
    const int P=1e9+7;
    inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
    inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
    inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
    inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
    int ksm(R int x,R int y){
        R int res=1;
        for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
        return res;
    }
    const int N=2e5+5,M=5005,S=2005;
    int a[N],b[N],fac[N],ifac[N],f[M][M],xmx,ymx,n,res;
    inline int C(R int n,R int m){return m>n?0:1ll*fac[n]*ifac[m]%P*ifac[n-m]%P;}
    void init(int n){
    	fac[0]=ifac[0]=1;
    	fp(i,1,n)fac[i]=mul(fac[i-1],i);
    	ifac[n]=ksm(fac[n],P-2);fd(i,n-1,1)ifac[i]=mul(ifac[i+1],i+1);
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
    	scanf("%d",&n);
    	fp(i,1,n)scanf("%d%d",&a[i],&b[i]),cmax(xmx,a[i]),cmax(ymx,b[i]);
    	init((xmx+ymx)<<1);
    	fp(i,1,n)++f[S-a[i]][S-b[i]];
    	fp(i,S-xmx,S+xmx)fp(j,S-ymx,S+ymx)if(f[i][j])upd(f[i+1][j],f[i][j]),upd(f[i][j+1],f[i][j]);
    	fp(i,1,n)upd(res,f[S+a[i]][S+b[i]]);
    	fp(i,1,n)res=dec(res,C((a[i]+b[i])<<1,a[i]<<1));
    	printf("%d
    ",mul(res,(P+1)>>1));
    	return 0;
    }
    

    (F)

    很妙的转化

    我们设一个新的序列(Q),其中(Q_{P_i}=i),那么操作可以变成“如果(|Q_i-Q_{i+1}|geq k),则可以交换(Q_i)(Q_{i+1})”,我们需要让(1)这个元素在最左边,在满足这个条件的时候让(2)在最左边,在满足这个条件时让(3)在最左边……

    假设在(Q)中存在(i,j)满足(i<j)(|Q_i-Q_j|<k),那么在(Q)(Q_i)(Q_j)左边,任意次操作之后(Q_i)也一定还在(Q_j)的左边

    此时我们可以从(Q_i)(Q_j)连一条边,易知连完边之后的图一定是一个(DAG),那么我们找到这个(DAG)最小的拓扑序就好了

    然而这样的话边数会爆炸

    考虑优化,若存在(i,j)满足(i<j)(j-i<k)(P_j<P_i),则在图中会连边(j,i),若(i)满足(i=min(l,P_l>P_j,lin[j-k+1,j-1])),则对于任意(l),必定有连边((j,l)),同时也必定有连边((i,l))!那么我们只需要连边((j,i)),即可满足拓扑的要求了。对于(j)的右边同样如此

    用线段树优化即可

    //quming
    #include<bits/stdc++.h>
    #define R register
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
    template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
    using namespace std;
    const int N=1e6+5,inf=0x3f3f3f3f;
    struct eg{int v,nx;}e[N<<1];int head[N],tot;
    inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
    inline int min(R int x,R int y){return x<y?x:y;}
    struct node;typedef node* ptr;
    struct node{
    	ptr lc,rc;int mn;
    	inline void upd(){mn=min(lc->mn,rc->mn);}
    }E[N<<2],*nd=E,*rt;
    priority_queue<int,vector<int>,greater<int> >q;int deg[N],pos[N],id[N],n,k;
    void build(ptr &p,int l,int r){
    	p=++nd;if(l==r)return p->mn=inf,void();
    	int mid=(l+r)>>1;
    	build(p->lc,l,mid),build(p->rc,mid+1,r);
    	p->upd();
    }
    void update(ptr p,int l,int r,int x,int v){
    	if(l==r)return p->mn=v,void();
    	int mid=(l+r)>>1;
    	x<=mid?update(p->lc,l,mid,x,v):update(p->rc,mid+1,r,x,v);
    	p->upd();
    }
    int res;
    void query(ptr p,int l,int r,int ql,int qr){
    	if(ql<=l&&qr>=r)return cmin(res,p->mn),void();
    	int mid=(l+r)>>1;
    	if(ql<=mid)query(p->lc,l,mid,ql,qr);
    	if(qr>mid)query(p->rc,mid+1,r,ql,qr);
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
    	scanf("%d%d",&n,&k);
    	for(R int i=1,x;i<=n;++i)scanf("%d",&x),pos[x]=i;
    	build(rt,1,n);
    	for(R int i=n,l,r;i;--i){
    		l=max(pos[i]-k+1,1),r=pos[i]-1,res=inf;
    		if(l<=r)query(rt,1,n,l,r);if(res!=inf)add(pos[i],pos[res]),++deg[pos[res]];
    		l=pos[i]+1,r=min(pos[i]+k-1,n),res=inf;
    		if(l<=r)query(rt,1,n,l,r);if(res!=inf)add(pos[i],pos[res]),++deg[pos[res]];
    		update(rt,1,n,pos[i],i);
    	}
    	fp(i,1,n)if(!deg[i])q.push(i);
    	for(R int u,i=1;i<=n;++i){
    		u=q.top(),q.pop(),id[u]=i;
    		go(u)if(!--deg[v])q.push(v);
    	}
    	fp(i,1,n)printf("%d
    ",id[i]);
    	return 0;
    }
    
  • 相关阅读:
    Linux 介绍了相关的文件夹
    mousewheel 与 DOMMouseScroll
    如何粗略分析关键词的优化难度
    好老师 (第九届湖南大学计算机程序设计竞赛)
    Java程序猿JavaScript学习笔记(14——扩大jQuery UI)
    在Ubuntu上为Android系统的Application Frameworks层增加硬件访问服务
    在Ubuntu为Android硬件抽象层(HAL)模块编写JNI方法提供Java访问硬件服务接口
    在Ubuntu上为Android增加硬件抽象层(HAL)模块访问Linux内核驱动程序
    在Ubuntu上为Android系统内置C可执行程序测试Linux内核驱动程序
    在Ubuntu上为Android系统编写Linux内核驱动程序
  • 原文地址:https://www.cnblogs.com/yuanquming/p/11311214.html
Copyright © 2020-2023  润新知