zoukankan      html  css  js  c++  java
  • Codeforces Round #576 (Div. 1)

    Codeforces Round #576 (Div. 1)

    https://codeforces.com/contest/1199

    虽然我打的是( m Div. ~2)但是因为( m Div. ~2)前两题实在是太水了这里就不说了。。

    不过涨了一百来$ m rating $还行(我果然分还是太低了)

    A. MP3

    算出可以接受的最大种类数然后对着题意模拟吧。。

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
     
    #define lf double
     
    #define pii pair<int,int >
    #define vec vector<int >
     
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
     
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
     
    const int maxn = 2e6+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
     
    int t[maxn],a[maxn],r[maxn],n,m,pre[maxn],suf[maxn];
     
    int main() {
        read(n),read(m),m<<=3;
        for(int i=1;i<=n;i++) read(a[i]),r[i]=a[i];
        sort(r+1,r+n+1);int l=unique(r+1,r+n+1)-r-1;
        for(int i=1;i<=n;i++) a[i]=lower_bound(r+1,r+l+1,a[i])-r,t[a[i]]++;
        for(int i=1;i<=n;i++) pre[i]=pre[i-1]+t[i];
        for(int i=n;i;i--) suf[i]=suf[i+1]+t[i];
        if(m/n>=20||(1<<(m/n))>=l) {return puts("0"),0;}
        int k=1<<(m/n),ans=1e9;
        for(int i=1;i<=l;i++)
            ans=min(ans,pre[i-1]+suf[i+k]);
        write(ans);
        return 0;
    }
    

    B. Welfare State

    好像有(O(n))的做法但是我直接拿线段树暴力模拟了。。

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
     
    #define lf double
     
    #define pii pair<int,int >
    #define vec vector<int >
     
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
     
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
     
    const int maxn = 1e6+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
     
    int n,a[maxn],q;
     
    #define ls p<<1
    #define rs p<<1|1
    #define mid ((l+r)>>1)
     
    struct Segment_Tree {
        int tag[maxn],mn[maxn];
     
        void push_tag(int p,int v) {
            // printf("push_tag :: %d %d
    ",p,v);
            if(tag[p]>=v) return ;
            if(mn[p]>=v) return ;
            tag[p]=v,mn[p]=v;
        }
     
        void pushdown(int p) {
            if(tag[p]==-1) return ;
            push_tag(ls,tag[p]),push_tag(rs,tag[p]);
            tag[p]=-1;
        }
     
        void cover(int p,int l,int r,int x,int y,int v) {
            if(mn[p]>=v) return ;
            if(x<=l&&r<=y) return push_tag(p,v),void();
            pushdown(p);
            if(x<=mid) cover(ls,l,mid,x,y,v);
            if(y>mid) cover(rs,mid+1,r,x,y,v);
            mn[p]=min(mn[ls],mn[rs]);
        }
     
        void modify(int p,int l,int r,int x,int v) {
            if(l==r) return tag[p]=-1,mn[p]=v,void();
            pushdown(p);
            if(x<=mid) modify(ls,l,mid,x,v);
            else modify(rs,mid+1,r,x,v);
            mn[p]=min(mn[ls],mn[rs]);
        }
     
        void print(int p,int l,int r) {
            if(l==r) printf("%d ",mn[p]);
            else pushdown(p),print(ls,l,mid),print(rs,mid+1,r);
        }
     
        void build(int p,int l,int r) {
            tag[p]=-1;
            if(l==r) mn[p]=a[l];
            else build(ls,l,mid),build(rs,mid+1,r),mn[p]=min(mn[ls],mn[rs]);
        }
     
        void debug(int p,int l,int r) {
            printf("debug :: %d %d %d %d
    ",l,r,tag[p],mn[p]);
            if(l==r) return ;
            else debug(ls,l,mid),debug(rs,mid+1,r);
        }
    }T;
     
    int main() {
        read(n);
        for(int i=1;i<=n;i++) read(a[i]);
        T.build(1,1,n);
        read(q);
        while(q--) {
            int op,x,y;read(op);
            if(op==1) read(x),read(y),T.modify(1,1,n,x,y);
            else read(x),T.cover(1,1,n,1,n,x);
            // printf("----------
    ");
            // T.debug(1,1,n);
        }T.print(1,1,n);puts("");
        return 0;
    }
    

    C. Matching vs Independent Set

    我们把边全连起来同时暴力的找到一个匹配,也就是每次判当前这条边能不能用,如果能就打个标记顺便标记下两个点。

    那么如果匹配数(geqslant n)就做完了,否则一定只有小于等于(2n)个点被标记了,剩下的就是独立集。

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
     
    #define lf double
     
    #define pii pair<int,int >
    #define vec vector<int >
     
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
     
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
     
    const int maxn = 1e6+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
     
    int d[maxn],c[maxn],n,m;
     
    void solve() {
        read(n),read(m);int t=0;
        for(int i=1;i<=m;i++) {
            int x,y;read(x),read(y);
            if(!d[x]&&!d[y]) d[x]++,d[y]++,c[i]=1,t++;
        }
        if(t>=n) {
            puts("Matching");
            for(int i=1,p=1;p<=n;i++)
                if(c[i]) printf("%d ",i),p++;
        } else {
            puts("IndSet");
            for(int i=1,p=1;p<=n;i++)
                if(!d[i]) printf("%d ",i),p++;
        }puts("");
    }
     
    void clear() {
        for(int i=1;i<=3*n;i++) d[i]=0;
        for(int i=1;i<=m;i++) c[i]=0;
    }
     
    int main() {
        int t;read(t);while(t--) solve(),clear();
        return 0;
    }
    

    D. Rectangle Painting 1

    大水题。。直接(dp)就好了。

    (f_{x1,y1,x2,y2})表示当前矩形的答案,显然每次要么把这个矩形涂满要么剖成两半转移。

    我写了个记搜结果跑的好慢啊。。。不过记搜是真的好写。

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
     
    #define lf double
     
    #define pii pair<int,int >
    #define vec vector<int >
     
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
     
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
     
    const int maxn = 1e6+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
     
    char c[52];
    int f[52][52][52][52],s[52][52],n;
     
    int dfs(int x1,int y1,int x2,int y2) {
        int &r=f[x1][x2][y1][y2];
        if(x1==x2&&y1==y2) return r=s[x1][y1];
        if(r<1e9) return r;
        r=max(x2-x1+1,y2-y1+1);
        for(int i=x1;i<=x2-1;i++)
            r=min(r,dfs(x1,y1,i,y2)+dfs(i+1,y1,x2,y2));
        for(int i=y1;i<=y2-1;i++)
            r=min(r,dfs(x1,y1,x2,i)+dfs(x1,i+1,x2,y2));
        // printf("dfs ::  %d %d %d %d %d
    ",x1,y1,x2,y2,r);
        return r;
    }
     
    int main() {
        read(n);
        for(int i=1;i<=n;i++) {
            scanf("%s",c+1);
            for(int j=1;j<=n;j++) s[i][j]=c[j]=='#';
        }memset(f,63,sizeof f);
        write(dfs(1,1,n,n));
        return 0;
    }
    

    E. Rectangle Painting 2

    这差不多就是原题了吧。。可以参考一下:[HNOI2013]消毒。

    思想就是每次消一整行或一整列,那么如果(n)不大,我们可以建二分图,左边表示每行,右边是列,每个黑点就弄一条边连向对应行列,答案就是最小点覆盖。

    (n)大的话离散化之后就变成了有点权的点覆盖,可以用最小割做。

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
     
    #define lf double
     
    #define pii pair<int,int >
    #define vec vector<int >
     
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
     
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
     
    const int maxn = 1e6+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
     
    int n,m,head[maxn],tot=1,c[102][102],rx[maxn],ry[maxn],s,t,dis[maxn];
    struct edge{int to,nxt,w;}e[maxn<<1];
    struct data {int x,y,xx,yy;}a[maxn];
     
    void prepare(int *r) {  
        r[++r[0]]=0,r[++r[0]]=n;
        sort(r+1,r+r[0]+1);r[0]=unique(r+1,r+r[0]+1)-r-1;
        // for(int i=1;i<=r[0];i++) printf("%d ",r[i]);puts("");
    }
     
    int get(int x,int *r) {
        return lower_bound(r+1,r+r[0]+1,x)-r;
    }
     
    void add(int u,int v,int w) {e[++tot]=(edge){v,head[u],w},head[u]=tot;}
    void ins(int u,int v,int w) {add(u,v,w),add(v,u,0);}
     
    int bfs() {
        queue<int > q;memset(dis,-1,sizeof dis);
        q.push(s);dis[s]=0;
        while(!q.empty()) {
            int x=q.front();q.pop();
            for(int i=head[x];i;i=e[i].nxt)
                if(e[i].w>0&&dis[e[i].to]==-1) {
                    dis[e[i].to]=dis[x]+1;
                    if(e[i].to==t) return 1;
                    q.push(e[i].to);
                }
        }return 0;
    }
     
    int dfs(int x,int f) {
        if(x==t) return f;
        int used=0;
        for(int i=head[x];i;i=e[i].nxt)
            if(e[i].w>0&&dis[e[i].to]==dis[x]+1) {
                int d=dfs(e[i].to,min(f,e[i].w));
                e[i].w-=d,e[i^1].w+=d,used+=d,f-=d;
                if(!f) break;
            }
        if(!used) dis[x]=-1;
        return used;
    }
     
    int max_flow() {
        int flow=0;
        while(bfs()) flow+=dfs(s,inf);
        return flow;
    }
     
    int main() {
        read(n),read(m);
        for(int i=1;i<=m;i++) {
            read(a[i].x),read(a[i].y),read(a[i].xx),read(a[i].yy);
            rx[++rx[0]]=a[i].x-1,rx[++rx[0]]=a[i].xx;
            ry[++ry[0]]=a[i].y-1,ry[++ry[0]]=a[i].yy;
        }
        prepare(rx),prepare(ry);s=rx[0]+ry[0]+3,t=s+1;
        for(int i=1;i<rx[0];i++) ins(s,i,rx[i+1]-rx[i]);
        for(int i=1;i<ry[0];i++) ins(i+rx[0],t,ry[i+1]-ry[i]);
        for(int i=1;i<=m;i++) {
            a[i].x=get(a[i].x-1,rx),a[i].xx=get(a[i].xx,rx);
            a[i].y=get(a[i].y-1,ry),a[i].yy=get(a[i].yy,ry);
            for(int k=a[i].x+1;k<=a[i].xx;k++)
                for(int l=a[i].y+1;l<=a[i].yy;l++)
                    c[k-1][l-1]=1;//,printf("%d %d
    ",k-1,l-1);
        }for(int i=1;i<rx[0];i++)
             for(int j=1;j<ry[0];j++)
                 if(c[i][j]) ins(i,j+rx[0],inf);
        write(max_flow());
        return 0;
    }
    

    F. GCD Groups 2

    大神题。。我弄了挺久才弄明白。

    首先注意到一个数最多只有(k=9)个质因子。

    假设我们现在知道了(a,b)在不同的集合,那么我们可以考虑消除每个质因子的影响。

    那么可以直接(dp),设(f_{s,t})表示左边集合(k)个质因子状态为(s),其中(0/1)表示有没有被消除,右边为(t)

    那么每次枚举状态,枚举当前数放左边还是右边就好了。

    这样(dp)复杂度是(O(2^{2k}cdot n))的。

    注意到我们一个集合至多只有(k+1)个有用的数,也就是说我们可以把其中的一个集合缩减到(k+1)个数,其他的扔到另一个集合里,方案仍然合法。

    所以如果我们任选(a,b),错误的概率为(frac{k+1}{n})

    所以我们直接随机化这个算法,期望只需要做(O(frac{n}{n-k+1}))次,因为(k)是常数所以这就是(O(1))次。

    那么我们得到了一个(O(2^{2k}cdot n))做法。

    考虑怎么优化,显然对于一个质因子至多只有(k)个数是有用的,那么一共只有(k^2)个数有用,剩下的都可以随便放。

    所以总复杂度为(O(2^{2k}cdot k^2+n))

    #include<bits/stdc++.h>
    using namespace std;
     
    void read(int &x) {
        x=0;int f=1;char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f;
    }
     
    void print(int x) {
        if(x<0) putchar('-'),x=-x;
        if(!x) return ;print(x/10),putchar(x%10+48);
    }
    void write(int x) {if(!x) putchar('0');else print(x);putchar('
    ');}
     
    #define lf double
     
    #define pii pair<int,int >
    #define vec vector<int >
     
    #define pb push_back
    #define mp make_pair
    #define fr first
    #define sc second
     
    #define FOR(i,l,r) for(int i=l,i##_r=r;i<=i##_r;i++)
     
    const int maxn = 1e6+10;
    const int inf = 1e9;
    const lf eps = 1e-8;
    const int mod = 1e9+7;
     
    int r[maxn],n,f[1100][1100],tt[maxn],w[2][1000],c[2][1000];
    struct data {int s,t,w;}pre[1100][1100];
     
    void factorize(int x,int *a) {
        memset(a,0,(sizeof x)*20);
        for(int i=2;i*i<=x;i++) {
            if(x%i) continue;
            a[++a[0]]=i;
            while(x%i==0) x/=i;
        }if(x!=1) a[++a[0]]=x;
    }
     
    int p[maxn];
     
    void prepare(int a,int b) {
        memset(c,0,sizeof c);
        memset(w,0,sizeof w);
        memset(p,0,sizeof p);
        factorize(r[a],w[0]),factorize(r[b],w[1]);
        // printf("factor ");for(int i=1;i<=w[0][0];i++) printf("%d ",w[0][i]);puts("");
        // printf("factor ");for(int i=1;i<=w[1][0];i++) printf("%d ",w[1][i]);puts("");
        for(int i=1;i<=n;i++) {
            if(i==a||i==b) continue;int bo=0;
            for(int o=0;o<=1;o++) {
                for(int k=1;k<=w[o][0];k++)
                    if(r[i]%w[o][k]) {
                        if(c[o][k]==w[o^1][0]) continue;
                        c[o][k]++,bo=1,p[++p[0]]=i;
                        break;
                    }
                if(bo) break;
            }
        }
    }
     
    int dp(int a,int b) {
        prepare(a,b);
        memset(tt,0,sizeof tt);
        memset(f,0,sizeof f);
        int k1=w[0][0],k2=w[1][0];
        f[(1<<k1)-1][(1<<k2)-1]=1;tt[a]=1,tt[b]=2;
        // for(int i=1;i<=p[0];i++) printf("%d ",p[i]);puts("");
        for(int i=1;i<=p[0];i++) {
            int s1=(1<<k1)-1,t1=(1<<k2)-1;
            for(int j=1;j<=k1;j++) if(r[p[i]]%w[0][j]) s1^=1<<(j-1);
            for(int j=1;j<=k2;j++) if(r[p[i]]%w[1][j]) t1^=1<<(j-1);
            for(int s=0;s<1<<k1;s++)
                for(int t=0;t<1<<k2;t++) {
                    if(!f[s][t]) continue;
                    if(!f[s&s1][t]) f[s&s1][t]=1,pre[s&s1][t]=(data){s,t,p[i]};
                    if(!f[s][t&t1]) f[s][t&t1]=1,pre[s][t&t1]=(data){s,t,p[i]};
                }
        }if(!f[0][0]) return 0;
        int s=0,t=0;
        while(!(s==(1<<k1)-1&&t==(1<<k2)-1)) {
            data d=pre[s][t];
            if(s!=d.s) tt[d.w]=1;
            else tt[d.w]=2;
            s=d.s,t=d.t;//printf("get :: %d %d %d
    ",s,t,d.w);
        }return 1;
    }
     
    int main() {
        read(n);srand(time(0));
        for(int i=1;i<=n;i++) read(r[i]);
        for(int T=1;T<=10;T++) {
            int a=rand()%n+1,b=rand()%n+1;
            if(a==b) continue;//printf("fuckpps :: %d %d
    ",a,b);
            if(!dp(a,b)) continue;
            puts("YES");
            for(int i=1;i<=n;i++) printf("%d ",tt[i]?tt[i]:1);
            return 0;
        }puts("NO");
        return 0;
    }
    
  • 相关阅读:
    P1843 奶牛晒衣服
    P1577 切绳子
    P2777 [AHOI2016初中组]自行车比赛——洛谷
    选择我自己的算法 2012年CCC加拿大高中生信息学奥赛
    如何修改博客园里个人首页背景(form:cot 大犇)
    洛谷P1105 平台
    SPFA模板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板板
    洛谷p2504 HAOI2006 聪明的猴子
    舒适的路线
    超级质数
  • 原文地址:https://www.cnblogs.com/hbyer/p/11418925.html
Copyright © 2011-2022 走看看