传送门: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]);
}