Codeforces Round #599 (Div. 2)

A. Maximum Square

直接O(kn^2)枚举最大边长

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int k,n,a[1005];
int main(){
    cin>>k;
    while(k--){
        cin>>n;
        for(int i=1;i<=n;++i) cin>>a[i];
        for(int i=n;i>=1;--i){
            int sum=0;
            for(int j=1;j<=n;++j)
                if(a[j]>=i) ++sum;
            if(sum>=i){printf("%d\n",i);break;}
        }
    }return 0;
}
View Code

B1. Character Swap (Easy Version)

合法当且仅当两串恰有2对相同的不同字符

(即$a[i]==a[j],b[i]==b[j],a[i]!=b[i]$)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int T,n,p[256][256];
char a[10005],b[10005];
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        scanf("%s",a+1);
        scanf("%s",b+1);
        memset(p,0,sizeof(p));
        for(int i=1;i<=n;++i)
            if(a[i]!=b[i])
                ++p[a[i]][b[i]];
        int sum=0;
        for(int i='a';i<='z';++i)
            for(int j='a';j<='z';++j){
                if(p[i][j]==2) ++sum;
                if(p[i][j]==1||p[i][j]>2) sum=5;
            }
        puts(sum<=1?"Yes":"No");
    }return 0;
}
View Code

B2. Character Swap (Hard Version)

$<=2n$次交换意味着可以直接模拟

不合法的情况当且仅当有字符在两串中出现次数为奇数

设当前到第$i$位,$a[i]!=b[i]$

直接枚举找与$a[i]$相同的字符$a[k]$或$b[k]$

如果为$a[k]$,$swap(b[i],a[k])$

如果为$b[k]$,选择任意一个下标$j$,$swap(a[j],b[k]),swap(a[j],b[i])$

这样每位最多交换2次

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int T,n,m,p1[256],r1[200],r2[200];
char a[53],b[53];
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        scanf("%s",a+1);
        scanf("%s",b+1);
        memset(p1,0,sizeof(p1));
        for(int i=1;i<=n;++i)
            ++p1[a[i]],++p1[b[i]];
        bool ok=1;
        for(int i='a';i<='z'&&ok;++i)
            if(p1[i]&1) ok=0;
        if(!ok){puts("No"); continue;}
        puts("Yes"); m=0;
        for(int i=1;i<=n;++i) if(a[i]!=b[i]){
            for(int j=i+1;j<=n;++j){
                if(a[j]==a[i]){
                    r1[++m]=j;
                    r2[m]=i;
                    swap(a[j],b[i]);
                    break;
                }
                if(b[j]==a[i]){
                    r1[++m]=i+1;
                    r2[m]=j;
                    swap(a[i+1],b[j]);
                    r1[++m]=i+1;
                    r2[m]=i;
                    swap(a[i+1],b[i]);
                    break;
                }
            }
        }
        printf("%d\n",m);
        for(int i=1;i<=m;++i) printf("%d %d\n",r1[i],r2[i]);
    }return 0;
}
View Code

C. Tile Painting

将$n$个点每隔$p-1(p>1,p|n)$个连边,求连通块个数

可以发现存在$p_1,p_2$时,连通块个数=$gcd(p_1,p_2)$

于是$O(\sqrt n)$枚举$n$的约数判断一下就好了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
ll n,m,p[300],tt,len;
int main(){
    cin>>n; m=len=n;
    for(ll i=2,t=sqrt(n);i<=t;++i){
        if(m<i) break;
        if(m%i==0) p[++tt]=i;
        while(m%i==0) m/=i;
    }
    if(m>1) p[++tt]=m;
    for(int i=tt;i>=1;--i){
        if(len%p[i]){len=1; break;}
        len=p[i];
    }cout<<len;
    return 0;
}
View Code

D. 0-1 MST

可以把0边用并查集维护,最后求连通块个数

但是$0$边过多

于是大力套个线段树优化建图就完事了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
#define N 100005
int n,m,fa[N*5],id[N]; bool vis[N*5],ve[N*5];
int rt,u,s[N*5],lc[N*5],rc[N*5];
vector <int> g[N];

int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void uni(int x,int y){
    int r1=find(x),r2=find(y);
    if(r1!=r2) fa[r1]=r2;
}
#define mid (l+r)/2
int build(int l,int r){
    int nw=++u;
    fa[nw]=nw;
    if(l==r){id[l]=nw; return nw;}
    lc[nw]=build(l,mid);
    rc[nw]=build(mid+1,r);
    return nw;
}
void link(int o,int l,int r,int x1,int x2,int k){
    if(x1<=l&&r<=x2){vis[o]=1; uni(o,k); return ;}
    if(x1<=mid) link(lc[o],l,mid,x1,x2,k);
    if(x2>mid) link(rc[o],mid+1,r,x1,x2,k);
}
void tree_uni(int o,int l,int r){
    if(vis[o]) for(int i=l;i<=r;++i) uni(o,id[i]);
    if(l==r) return ;
    tree_uni(lc[o],l,mid); tree_uni(rc[o],mid+1,r);
}
void Link(int I,int l,int r){
    link(rt,1,n,l,r,id[I]);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1,U,V;i<=m;++i){
        scanf("%d%d",&U,&V);
        g[U].push_back(V);
        g[V].push_back(U);
    }
    rt=build(1,n);
    for(int i=1;i<=n;++i){
        g[i].push_back(i);
        sort(g[i].begin(),g[i].end());
        int len=g[i].size();
        for(int j=0;j<len-1;++j){
            int l=g[i][j],r=g[i][j+1];
            if(l+1<r) Link(i,l+1,r-1);
        }
        if(1<g[i][0]) Link(i,1,g[i][0]-1);
        if(g[i][len-1]<n) Link(i,g[i][len-1]+1,n);
    }
    tree_uni(rt,1,n);
    int tot=0;
    for(int i=1;i<=n;++i){
        int Fa=find(id[i]);
        if(!ve[Fa]) ve[Fa]=1,++tot;
    }
    printf("%d",tot-1);
    return 0;
}
View Code

E. Sum Balance

WA#9......不管了先睡了(错乱)

posted @ 2019-11-07 02:43  kafuuchino  阅读(237)  评论(0编辑  收藏  举报