• Codeforces Global Round 16部分题解


    A.Median Maximization

    比较简单显而易见的贪心,显然前(lfloorfrac{m-1}{2} floor)数是(0),后面的数尽可能平均分。

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<map>
    #include<queue>
    #include<time.h>
    #include<set>
    using namespace std;
    #define rg register
    #define ll long long
    #define ull unsigned long long
    #define lowbit(i) i&(-i)
    #define pb(x) push_back(x)
    void read(int &x){
        char ch;bool ok;
        for(ok=0,ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')ok=1;
        for(x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());if(ok)x=-x;
    }
    const int maxn=1e5+10,mod=1e9+7;
    int T,n,s;
    int main(){
        read(T);
        while(T--){
            read(n),read(s);
    	printf("%d
    ",s/(n-(n+1)/2+1));
        }
    }
    

    B.MIN-MEX Cut

    首先发现对于(1)来说,( m MEX(1)=0,MEX(1...1)=0)

    而对于(0)来说,( m MEX(0)=1,MEX(0...0)=1),因此一段(0)的答案最优显然是(1)

    可以发现的一点是( m MEX(01)=2),所以答案显然小于(2)

    因此,我们只需要计算出(0)的段数就可以得出答案了

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<map>
    #include<queue>
    #include<time.h>
    #include<set>
    using namespace std;
    #define rg register
    #define ll long long
    #define ull unsigned long long
    #define lowbit(i) i&(-i)
    #define pb(x) push_back(x)
    void read(int &x){
        char ch;bool ok;
        for(ok=0,ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')ok=1;
        for(x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());if(ok)x=-x;
    }
    const int maxn=1e5+10,mod=1e9+7;
    int T,n,m;char a[maxn];
    int main(){
        read(T);
        while(T--){
    	scanf("%s",a+1);n=strlen(a+1);m=0;
    	for(rg int i=1;i<=n;i++)if(a[i]!=a[i-1]&&a[i]=='0')m++;
    	if(m>=2)m=2;printf("%d
    ",m);
        }
    }
    

    C.MAX-MEX Cut

    这个题目可以说是上面那题的升级版

    考虑方法是一致的

    对于每一列,有三种情况:

    1、同为(1),那么( m MEXegin{bmatrix}1\1 end{bmatrix}=0)

    2、同为(0),那么( m MEXegin{bmatrix}0\0 end{bmatrix}=1)

    3、不相同,那么( m MEXegin{bmatrix}0\1 end{bmatrix}=2, m MEXegin{bmatrix}1\0 end{bmatrix}=2)

    简单分析可知,前两种情况组合可以得到更大的价值。

    所以我们只需要前两种情况能组合就组合就行了。

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<map>
    #include<queue>
    #include<time.h>
    #include<set>
    using namespace std;
    #define rg register
    #define ll long long
    #define ull unsigned long long
    #define lowbit(i) i&(-i)
    #define pb(x) push_back(x)
    void read(int &x){
        char ch;bool ok;
        for(ok=0,ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')ok=1;
        for(x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());if(ok)x=-x;
    }
    const int maxn=1e5+10,mod=1e9+7;
    int T,n,m,b[maxn],vis[maxn];char a[2][maxn];
    int main(){
        read(T);
        while(T--){
    	read(n);
    	scanf("%s",a[0]+1);m=0;scanf("%s",a[1]+1);
    	for(rg int i=1;i<=n;i++){
    	    if(a[0][i]=='1'&&a[1][i]=='1')b[i]=1;
    	    if(a[0][i]=='0'&&a[1][i]=='0')b[i]=2;
    	    if(a[0][i]=='0'&&a[1][i]=='1')b[i]=0;
    	    if(a[0][i]=='1'&&a[1][i]=='0')b[i]=0;
    	}
    	for(rg int i=1;i<=n;i++){
    	    if(b[i]==0)m+=2;
    	    if(b[i]==2)m+=1;
    	    if(b[i]==1){
    		if(b[i-1]==2&&!vis[i-1])m++;
    		else if(b[i+1]==2)vis[i+1]=1,m++;
    	    }
    	}
    	for(rg int i=1;i<=n;i++)vis[i]=b[i]=0;
    	printf("%d
    ",m);
        }
    }
    

    D.Seating Arrangements (hard version)

    直接考虑( m hard version)

    本题实际上就是模拟。统计出每个数字可以填的范围。

    然后贪心的考虑显然要使得当前填的数尽可能小的影响到其他数,也就是每一行优先填最右边的位置

    用指针记录一下每个数填过哪些位置就行了

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<map>
    #include<queue>
    #include<time.h>
    #include<set>
    using namespace std;
    #define rg register
    #define ll long long
    #define ull unsigned long long
    #define lowbit(i) i&(-i)
    #define pb(x) push_back(x)
    void read(int &x){
        char ch;bool ok;
        for(ok=0,ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')ok=1;
        for(x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());if(ok)x=-x;
    }
    const int maxn=310,mod=1e9+7;
    int T,n,m,ans,a[maxn*maxn],f[maxn][maxn],b[maxn*maxn];
    struct oo{int x,y;}l[maxn*maxn],r[maxn*maxn],d[maxn*maxn];
    map<int,int>mp;
    int main(){
        read(T);
        while(T--){
    	memset(f,0,sizeof f);
    	memset(l,0,sizeof l);
    	memset(r,0,sizeof r);
    	memset(d,0,sizeof d);
    	memset(b,0,sizeof b);
    	memset(a,0,sizeof a);
    	mp.clear();
    	read(n),read(m);ans=0;
    	for(rg int i=1;i<=n*m;i++)read(a[i]),b[i]=a[i];
    	sort(b+1,b+n*m+1);int g=0,s=1;
    	for(rg int i=1;i<=n*m;i++)if(!mp[b[i]])mp[b[i]]=++g;
    	for(rg int i=1;i<=n*m;i++)
    	    if(b[i]!=b[i+1]){
    		l[mp[b[i]]]=(oo){(s-1)/m+1,(s-1)%m+1};
    		r[mp[b[i]]]=(oo){(i-1)/m+1,(i-1)%m+1};
    		if(r[mp[b[i]]].x>l[mp[b[i]]].x)d[mp[b[i]]]=(oo){l[mp[b[i]]].x,m};
    		else d[mp[b[i]]]=r[mp[b[i]]];
    		s=i+1;
    	    }
    	for(rg int i=1;i<=n*m;i++){
    	    int xx=d[mp[a[i]]].x,yy=d[mp[a[i]]].y;
    	    for(rg int j=1;j<=yy;j++)if(f[xx][j])ans++;
    	    f[xx][yy]=1;d[mp[a[i]]].y--;
    	    if(d[mp[a[i]]].x==l[mp[a[i]]].x&&d[mp[a[i]]].y<l[mp[a[i]]].y){
    		d[mp[a[i]]].x++,d[mp[a[i]]].y=m;
    		if(d[mp[a[i]]].x==r[mp[a[i]]].x)d[mp[a[i]]].y=r[mp[a[i]]].y;
    	    }
    	    else if(d[mp[a[i]]].y<1){
    		d[mp[a[i]]].x++,d[mp[a[i]]].y=m;
    		if(d[mp[a[i]]].x==r[mp[a[i]]].x)d[mp[a[i]]].y=r[mp[a[i]]].y;
    	    }
    	}
    	printf("%d
    ",ans);
        }
    }
    

    E.Buds Re-hanging

    考虑每切下一个( m bud),我们有两种情况:

    1、多出一个叶子节点,然后我们将该( m bud)接到一个叶子上,又可以减少一个叶子节点,总的来说叶子节点数不变

    2、叶子节点数不变,然后我们将该( m bud)接到一个叶子上,减少一个叶子节点,总的来说叶子节点数减少(1)

    因此切下( m bud)显然是不劣的

    最优的情况显然是( m bud-叶子-bud-叶子)这样的,所以我们只需要统计出有多少个( m bud)就行了,然后这样排列就行了

    一个细节是处理一下根是否有叶子节点

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<map>
    #include<queue>
    #include<time.h>
    #include<set>
    using namespace std;
    #define rg register
    #define ll long long
    #define ull unsigned long long
    #define lowbit(i) i&(-i)
    #define pb(x) push_back(x)
    void read(int &x){
        char ch;bool ok;
        for(ok=0,ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')ok=1;
        for(x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());if(ok)x=-x;
    }
    const int maxn=2e5+10,mod=1e9+7;
    int T,n,m,ans;bool used[maxn];
    int cnt,pre[maxn*2],nxt[maxn*2],h[maxn];
    void add(int x,int y){
        pre[++cnt]=y,nxt[cnt]=h[x],h[x]=cnt;
        pre[++cnt]=x,nxt[cnt]=h[y],h[y]=cnt;
    }
    void dfs(int x,int fa){
        int f=0;
        for(rg int i=h[x];i;i=nxt[i])
    	if(pre[i]!=fa){
    	    dfs(pre[i],x);
    	    if(!used[pre[i]])f=1;
    	}
        if(f&&x!=1)used[x]=1,m++;
        if(x==1){
    	if(f)ans=-1;
    	else ans=0;
        }
    }
    int main(){
        read(T);
        while(T--){
    	read(n);m=cnt=0;
    	for(rg int i=1,x,y;i<n;i++)read(x),read(y),add(x,y);
    	dfs(1,0);printf("%d
    ",ans+n-m*2);
    	for(rg int i=1;i<=n;i++)used[i]=0,h[i]=0;
        }
    }
    

    F.Points Movement

    显然初始情况下就已经满足条件的区间是没用的

    然后对点和剩下的区间分别排个序。

    (a_i)是第(i)点的初始坐标

    显然的是第(i)个点的移动范围一定在(a_{i-1})(a_{i+1})之间,因为如果超过前后两个点,用那两个点一定更优

    用这个结论,我们就可以确定出一个点能处理的区间有哪些了。

    一个显然的结论是:前(i)个点要处理掉所有在(a_i)之前的区间

    那么我们可以设出(f[i][j])表示当前考虑了前(i)个点,处理了前(j)个区间的最小代价。

    (i)个点至少要处理的区间是前(v_i)

    状态转移略微复杂:

    1、假如当前考虑前(i-1)个点处理到了前(k)个区间,第(i)个点只处理到(v_i),那么我们只需要向左移动就行了

    2、假如当前考虑前(i-1)个点处理到了前(k)个区间,第(i)个点处理前(t(v_i<tleq v_{i+1}))个区间,那么我们就有两种走法,先左移再向右移,或是先向右移再左移,这个地方的代价有些不好处理。因为对于每个(t),向右的距离是固定的,两种走法分别计算一下最小值就行了

    3、假如当前考虑前(i-1)个点处理到了前(v_i)个区间,那么第(i)个点就可以考虑只右移即可

    一共三种情况,该题范围(2 imes 10^5),所以滚动第一维即可

    该题每个点只被访问(1)次,区间只被访问(2)次,总复杂度(O(n))

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<map>
    #include<queue>
    #include<time.h>
    #include<set>
    using namespace std;
    #define rg register
    #define ll long long
    #define ull unsigned long long
    #define lowbit(i) i&(-i)
    #define pb(x) push_back(x)
    void read(int &x){
        char ch;bool ok;
        for(ok=0,ch=getchar();!isdigit(ch);ch=getchar())if(ch=='-')ok=1;
        for(x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());if(ok)x=-x;
    }
    const int maxn=2e5+10,mod=1e9+7;
    int n,a[maxn],T,m,v[maxn],tot,cc[maxn];
    ll f[2][maxn],g[maxn],ans=1e18;
    struct oo{int l,r;}d[maxn],c[maxn];
    bool cmp(oo a,oo b){return a.l<b.l;}
    int main(){
        read(T);
        while(T--){
    	read(n),read(m);tot=0;ans=1e18;
    	for(rg int i=1;i<=n;i++)read(a[i]);
    	sort(a+1,a+n+1);
    	for(rg int i=1;i<=m;i++)read(d[i].l),read(d[i].r);
    	sort(d+1,d+m+1,cmp);
    	for(rg int i=1;i<=m;i++){
    	    int s=lower_bound(a+1,a+n+1,d[i].l)-a,t=upper_bound(a+1,a+n+1,d[i].r)-a-1;
    	    if(s>t)c[++tot]=d[i],cc[tot]=d[i].r;
    	}
    	for(rg int i=1;i<=n;i++)v[i]=upper_bound(cc+1,cc+tot+1,a[i])-cc-1;
    	v[n+1]=tot;v[0]=0;f[0][0]=0;
    	for(rg int i=1;i<=tot;i++)f[0][i]=1e18;
    	for(rg int i=1;i<=n;i++){
    	    f[i&1][0]=0;
    	    for(rg int j=1;j<=tot;j++)f[i&1][j]=f[(i&1)^1][j],g[j]=1e18;
    	    int now=2e9;
    	    for(rg int j=v[i];j>v[i-1];j--){
    		now=min(now,c[j].r);
    	        f[i&1][v[i]]=min(f[i&1][v[i]],f[(i&1)^1][j-1]+a[i]-now);
    	    }
    	    now=2e9;
    	    for(rg int j=v[i];j>v[i-1];j--){
    		now=min(now,c[j].r);
    	        g[v[i]]=min(g[v[i]],f[(i&1)^1][j-1]+2ll*(a[i]-now));
    	    }
    	    now=-2e9;
    	    for(rg int j=v[i]+1;j<=v[i+1];j++){
    		now=max(now,c[j].l);
    		f[i&1][j]=min(f[i&1][j],f[i&1][v[i]]+2ll*(now-a[i]));
    		f[i&1][j]=min(f[i&1][j],g[v[i]]+now-a[i]);
    		f[i&1][j]=min(f[i&1][j],f[(i&1)^1][v[i]]+now-a[i]);
    	    }
    	    ans=min(ans,f[i&1][tot]);
    	}
    	printf("%lld
    ",ans);
        }
    }
    
  • 相关阅读:
    JavaScript对象
    JavaScript基础
    MySQL总结
    前端的基础知识汇总
    反射,面对对象高阶
    django中的认证登陆与用户的创建
    django的cookie和session
    ajax的json包含于xml的区别
    django的分页系统
    django的orm简签
  • 原文地址:https://www.cnblogs.com/lcxer/p/15302775.html
Copyright © 2020-2023  润新知