CF1198 Div1做题记录

发布时间 2023-05-09 15:18:39作者: luo_shen

A

CF题面

排序,前缀和统计 \(\left[1,i\right]\) 内有多少不同数字,枚举 \(l\),二分 \(r\),显然的是 \(l,r\) 等于某一个数字最好,所以可以得到对于每个 \(l\),最多有多少数字不被修改。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=4e5+10;
int n,x,a[N],ans,s[N];
void solve(){
    read(n),read(x);
    x*=8;
    ans=n;
    for(int i=1;i<=n;i++){
        read(a[i]);
    }
    sort(a+1,a+n+1);
    s[1]=1;
    for(int i=2;i<=n;i++){
        s[i]=s[i-1];
        if(a[i]!=a[i-1]){
            s[i]++;
        }
    }
    for(int i=1;i<=n;i++){
        int l=i,r=n,pos=n+1;
        while(l<=r){
            int mid=(l+r)>>1;
            double y=ceil(log2(s[mid]-s[i]+1));
            if(y*n<=x){
                pos=mid;
                l=mid+1;
            }
            else{
                r=mid-1;
            }
        }
        ans=min(ans,n-(pos-i+1));
    }
    write_endl(ans);
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}

B

CF题面

正着模拟不好处理,考虑反过来。

假设当前正在处理第 \(i\) 次操作,令它为操作 \(1\)。显然当后面有操作 \(1\) 时,该操作为无效操作。后面操作 \(2\) 的值的 \(\max\)\(mx\) 会影响当前位置最终赋的值,所以将当前位置的值赋为 \(\max(mx,x)\),并打上标记。对于到最后还没有被进行过操作 \(1\) 的位置,将值与 \(mx\)\(\max\)

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=2e5+10;
int n,Q,a[N],tag[N];
struct node{
    int opt,p,x;
}q[N];
void solve(){
    read(n);
    for(int i=1;i<=n;i++){
        read(a[i]);
    }
    read(Q);
    for(int i=1;i<=Q;i++){
        read(q[i].opt);;
        if(q[i].opt==1){
            read(q[i].p),read(q[i].x);
        }
        else{
            read(q[i].x);
        }
    }
    int mn=0;
    for(int i=Q;i;i--){
        if(q[i].opt==1){
            if(!tag[q[i].p]){
                tag[q[i].p]=1;
                a[q[i].p]=max(q[i].x,mn);
            }
        }
        else{
            mn=max(mn,q[i].x);
        }
    }
    for(int i=1;i<=n;i++){
        if(!tag[i]){
            a[i]=max(a[i],mn);
        }
        write_space(a[i]);
    }
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}

C

CF题面

对于一条边,如果两个端点都还没选,那么选择这条边和两个端点。被选择的边代表一个匹配,不被选择的点代表一个独立集。根据操作过程可知,其中必有一个大小大于等于 \(n\)

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
int n,m;
void solve(){
    read(n),read(m);
    set<int>s1,s2;
    for(int i=1;i<=n*3;i++){
        s1.insert(i);
    }
    for(int i=1,u,v;i<=m;i++){
        read(u),read(v);
        if(s1.count(u)&&s1.count(v)){
            s1.erase(u),s1.erase(v);
            s2.insert(i);
        }
    }
    if(s1.size()>=n){
        puts("IndSet");
        int s=0;
        while(s<n){
            write_space(*s1.begin());
            s1.erase(s1.begin());
            s++;
        }
    }
    else{
        puts("Matching");
        int s=0;
        while(s<n){
            write_space(*s2.begin());
            s2.erase(s2.begin());
            s++;
        }
    }
    putchar('\n');
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t;
    read(t);
    while(t--){
        solve();
    }
    return 0;
}

D

CF题面

\(f_{xl,yl,xr,yr}\) 表示左上角为 \((xl,yl)\),右下角为 \((xr,yr)\) 的矩形的答案,记忆化搜索即可。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=60,inf=0x3f3f3f3f;
int n,f[N][N][N][N];
char ch[N][N];
int dfs(int xl,int yl,int xr,int yr){
    if(f[xl][yl][xr][yr]!=inf){
        return f[xl][yl][xr][yr];
    }
    if(xl==xr&&yl==yr){
        f[xl][yl][xr][yr]=(ch[xl][yl]=='#');
        return f[xl][yl][xr][yr];
    }
    for(int i=xl;i<xr;i++){
        f[xl][yl][xr][yr]=min(f[xl][yl][xr][yr],dfs(xl,yl,i,yr)+dfs(i+1,yl,xr,yr));
    }
    for(int i=yl;i<yr;i++){
        f[xl][yl][xr][yr]=min(f[xl][yl][xr][yr],dfs(xl,yl,xr,i)+dfs(xl,i+1,xr,yr));
    }
    f[xl][yl][xr][yr]=min(f[xl][yl][xr][yr],max(xr-xl+1,yr-yl+1));
    return f[xl][yl][xr][yr];
}
void solve(){
    memset(f,inf,sizeof(f));
    read(n);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            ch[i][j]=getchar();
            while(ch[i][j]!='.'&&ch[i][j]!='#'){
                ch[i][j]=getchar();
            }
        }
    }
    write_endl(dfs(1,1,n,n));
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}

E

CF题面

第一下看错了题,以为和D是一样的题意,只是放大了数据,仔细一看发现贡献从矩形两边的最大值变成了最小值。这样,每次选择的矩形变成了 \(1\times \infty\)\(\infty\times 1\)。题意变成了可以选择一些行和一些列,覆盖到所有矩形,并使所选行和列的数量之和最少。对于一个矩形,它要么选择所有的行,要么选择所有的列,将行和列之间连边,就变成了二分图最大匹配问题了。

但这不够,考虑离散化,将矩形的右边界和下边界拓宽一格,这时矩形被表示为了 \([xl,xr),[yl,yr)\)。令离散化后的直线 \(x_i,y_i\) 表示 \([x_i,x_{i+1}),[y_i,y_{i+1})\) 这个区间。很容易发现这和原来的二分图匹配仍然等价,因为一个区间里直线要么全选,要么全不选。将原来在一个矩形里的两条线连边,跑网络流即可。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=210,inf=1e9,M=2e5+10;
int x[N],y[N],n,m,cntx,cnty;
struct node{
    int xl,xr,yl,yr;
}mat[N];
int head[N],S,T,tot=1,dep[N],cur[N];
struct edge{
    int v,w,nxt;
}e[M];
void add(int u,int v,int w){
    e[++tot].v=v;
    e[tot].w=w;
    e[tot].nxt=head[u];
    head[u]=tot;
}
bool bfs(int S,int T){
    for(int i=1;i<=T;i++){
        dep[i]=0;
    }
    queue<int>q;
    q.push(S);
    dep[S]=1;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].v,w=e[i].w;
            if(w&&!dep[v]){
                dep[v]=dep[u]+1;
                if(v==T){
                    return 1;
                }
                q.push(v);
            }
        }
    }
    return 0;
}
int dfs(int u,int flow,int T){
    if(u==T){
        return flow;
    }
    int s=0;
    for(int i=cur[u];i;i=e[i].nxt){
        int v=e[i].v,w=e[i].w;
        if(w&&dep[v]==dep[u]+1){
            int res=dfs(v,min(flow,w),T);
            e[i].w-=res;
            e[i^1].w+=res;
            s+=res;
            flow-=res;
        }
        if(!flow){
            break;
        }
    }
    if(!s){
        dep[u]=0;
    }
    return s;
}
int dinic(int S,int T){
    int sum=0;
    while(bfs(S,T)){
        for(int i=1;i<=T;i++){
            cur[i]=head[i];
        }
        sum+=dfs(S,inf,T);
    }
    return sum;
}
void solve(){
    read(n),read(m);
    for(int i=1;i<=m;i++){
        read(mat[i].xl),read(mat[i].yl),read(mat[i].xr),read(mat[i].yr);
        mat[i].xr++,mat[i].yr++;
        x[++cntx]=mat[i].xl,x[++cntx]=mat[i].xr;
        y[++cnty]=mat[i].yl,y[++cnty]=mat[i].yr;
    }
    sort(x+1,x+cntx+1);
    sort(y+1,y+cnty+1);
    cntx=unique(x+1,x+cntx+1)-x-1;
    cnty=unique(y+1,y+cnty+1)-y-1;
    for(int i=1;i<=m;i++){
        mat[i].xl=lower_bound(x+1,x+cntx+1,mat[i].xl)-x;
        mat[i].xr=lower_bound(x+1,x+cntx+1,mat[i].xr)-x;
        mat[i].yl=lower_bound(y+1,y+cnty+1,mat[i].yl)-y;
        mat[i].yr=lower_bound(y+1,y+cnty+1,mat[i].yr)-y;
        for(int j=mat[i].xl;j<mat[i].xr;j++){
            for(int k=mat[i].yl;k<mat[i].yr;k++){
                add(j,k+cntx,inf);
                add(k+cntx,j,0);
            }
        }
    }
    S=cntx+cnty+1,T=cntx+cnty+2;
    for(int i=1;i<cntx;i++){
        add(S,i,x[i+1]-x[i]);
        add(i,S,0);
    }
    for(int i=1;i<cnty;i++){
        add(i+cntx,T,y[i+1]-y[i]);
        add(T,i+cntx,0);
    }
    write_endl(dinic(S,T));
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}

F

CF题面

令两组的 \(\gcd\) 分别为 \(g_1,g_2\)
先假设已知放数的顺序,怎么放是最优的。有一个贪心的想法,假如 \(g_1\)\(a_i\) 的因子,那么放到第一组里肯定不会是 \(g_1\) 变小,所以将 \(a_i\) 放到第二组后肯定不劣于放到第一组。
所以我们随机放数顺序,当随机一定多组后还不行,则答案为NO。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
using namespace std;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=1e5+10;
int n,a[N],id[N],g[2],ans[N];
bool work(){
    ans[id[1]]=1;
    g[1]=a[id[1]];
    ans[id[2]]=2;
    g[2]=a[id[2]];
    for(int i=3;i<=n;i++){
        if(a[id[i]]%g[1]){
            ans[id[i]]=1;
            g[1]=__gcd(a[id[i]],g[1]);
        }
        else{
            ans[id[i]]=2;
            g[2]=__gcd(a[id[i]],g[2]);
        }
    }
    return (g[1]==1)&&(g[2]==1);
}
void solve(){
    srand((unsigned)time(NULL));
    read(n);
    for(int i=1;i<=n;i++){
        read(a[i]);
        id[i]=i;
    }
    int T=min(500,10000000/n/2);
    while(T--){
        random_shuffle(id+1,id+n+1);
        if(work()){
            puts("YES");
            for(int i=1;i<=n;i++){
                write_space(ans[i]);
            }
            return;
        }
    }
    puts("NO");
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}