「Codeforces Round 576 (div2)」题解

传送门:https://codeforces.com/contest/1199

C. MP3

题解

  • 尺取法

代码

#include
 
using namespace std;
const int maxn=4e5+10;
 
int n,m,a[maxn],num[maxn],tot=0,sum[maxn];
 
int solve(int k)
{
    return (int)ceil(log2((double)k));
}
 
int main()
{
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    sort(a+1,a+n+1);int last=0;
    for(int i=1;i<=n;i++) if(i!=1&&a[i]!=a[i-1]) num[++tot]=i-1-last,last=i-1;
    num[++tot]=n-last;
    for(int i=1;i<=tot;i++) sum[i]=sum[i-1]+num[i];
    int l=1,r=0;int ans=0x3f3f3f3f;
    while(l<=tot||r<=tot) {
        while(r<=tot&&solve(r-l+1)*n<=8*m) r++;
        if(solve(r-l)*n<=8*m) ans=min(ans,n-sum[r-1]+sum[l-1]);
        l++;
    }
    printf("%d\n",ans);
}

D. Welfare State

题意

  • 就是给你一个数组,两种操作,第一种是修改某个位置的值,另一种是将当前数组中所有小于 x x x的数改成 x x x

题解

  • 首先对于每一个 1 1 1操作,考虑他后面所有的 2 2 2操作的最大 x x x值,与当前该位置值取 m a x max max后就是它这个位置最后的值,最后遍历整个数组,如果某个位置没有被 1 1 1操作过,那么这个位置与最大的 x x x m a x max max就是最后该位置的值

代码

#include
 
using namespace std;
 
const int maxn=2e5+10;
int n,a[maxn],maxx[maxn],opt[maxn],c[maxn][2],b[maxn],flag[maxn];
 
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    int q;scanf("%d",&q);
    for(int i=1;i<=q;i++) {
        scanf("%d",&opt[i]) ;
        if(opt[i]==1) {
            scanf("%d %d",&c[i][0],&c[i][1]);
            flag[c[i][0]]=1;
        }else{
            scanf("%d",&b[i]);
        }
    }
 
    memset(maxx,-1,sizeof(maxx));
    for(int i=q;i>=1;i--) {
        if(opt[i]==2) {
            maxx[i]=max(b[i],maxx[i+1]);
        }else maxx[i]=maxx[i+1];
    }
 
    for(int i=1;i<=q;i++) {
        if(opt[i]==1) {
            a[c[i][0]]=c[i][1];
            if(maxx[i+1]>a[c[i][0]]) {
                a[c[i][0]]=maxx[i+1];
            }
        }
    }
 
    int opt2=-1;
    for(int i=1;i<=q;i++) if(opt[i]==2&&b[i]>opt2) opt2=b[i];
    for(int i=1;i<=n;i++) if(!flag[i]&&a[i]<opt2) a[i]=opt2;
 
    for(int i=1;i<=n;i++) printf("%d%c",a[i],i==n?'\n':' ');
}

E. Matching vs Independent Set

题意

  • 就是给你一个含有 3 × n 3\times n 3×n个节点, m m m条边构成的图,求一个含有 n n n条边的匹配或者 n n n个节点的独立集,两者都不存在的话输出 I m p o s s i b l e Impossible Impossible

题解

  • 至于为什么是 3 × n 3\times n 3×n个节点呢?咱也不知道 233 233 233
  • 考虑从任意一条边找到一个匹配,能加边就加,那么最后剩下的点的状态就是任意两个点之间没有边相连,如果找到了大小为 n n n的匹配,直接返回,否则可以根据找匹配过程后未使用的节点中的任意 n n n个即为独立集,而且显然一定能找到这样的独立集,因为如果没有 n n n条匹配的边,那么用过的点数 < 2 × n <2\times n <2×n,也就说明能找到大于 n n n个点的独立集
  • 所以说没必要取找一个最大的匹配,显然答案一定有解

代码

#include

using namespace std;
const int maxn=3e5+10;
const int maxm=5e5+10;

int x[maxm],y[maxm],vis[maxn],n,m;
int edge[maxm],tot1,node[maxn],tot2;

bool work1()
{
    tot1=tot2=0;
    for(int i=1;i<=3*n;i++) vis[i]=0;
    for(int i=1;i<=m;i++) if(!vis[x[i]]&&!vis[y[i]]) {
        vis[x[i]]=vis[y[i]]=1;
        edge[++tot1]=i;
    }
    if(tot1>=n) {
        printf("Matching\n");
        for(int i=1;i<=n;i++) printf("%d%c",edge[i],i==n?'\n':' ');
        return true;
    }
    return false;
}

bool work2()
{
    for(int i=1;i<=3*n;i++) if(!vis[i]) node[++tot2]=i;
    if(tot2>=n) {
        printf("IndSet\n");
        for(int i=1;i<=n;i++) printf("%d%c",node[i],i==n?'\n':' ');
        return true;
    }
    return false;
}

int main()
{
    int t;scanf("%d",&t);
    while(t--) {
        scanf("%d %d",&n,&m);
        for(int i=1;i<=m;i++) scanf("%d %d",&x[i],&y[i]);
        if(!work1()&&!work2()) printf("Impossible\n"); 
    }
}

F. Rectangle Painting 1

题意

  • 给你一个 n × n n \times n n×n的矩阵,每个位置为黑或者白,每次可以选一个 h × w h\times w h×w的子矩阵并将其内所有位置涂白,对应的代价为 m a x ( h , w ) max(h,w) max(h,w),求将这个矩阵全部涂白的最小代价

题解

  • d p dp dp
  • 考虑将当前矩阵上下分成两半或者左右分成两半进行转移

代码

#include
 
using namespace std;
const int maxn=55;
 
int n,dp[maxn][maxn][maxn][maxn];
char s[maxn][maxn];
 
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
    for(int h=1;h<=n;h++) {
        for(int w=1;w<=n;w++) {
            for(int i=1;i+h-1<=n;i++) {
                for(int j=1;j+w-1<=n;j++) {
                    if(w==1&&h==1) {dp[i][j][h][w]=(s[i][j]=='#');continue;}
                    dp[i][j][h][w]=max(h,w);
 
                    for(int k=1;k<h;k++) dp[i][j][h][w]=min(dp[i][j][h][w],dp[i][j][k][w]+dp[i+k][j][h-k][w]);
                    for(int k=1;k<w;k++) dp[i][j][h][w]=min(dp[i][j][h][w],dp[i][j][h][k]+dp[i][j+k][h][w-k]);
                }
            }
        }
    }
    printf("%d\n",dp[1][1][n][n]);
}

你可能感兴趣的:(思维,dp)