点此进入比赛

\(A\):MP3(点此看题面)

大致题意: 让你选择一个值域区间\([L,R]\),使得序列中满足\(L\le a_i\le R\)的数的种类数不超过\(2^{\lfloor\frac {8I}n\rfloor}\),输出剩余数的数量的最小值。

对着英文题面懵了半天。。。

理解题意之后这题就很水了。

考虑我们先排序+离散化,然后选择的数必然是离散化序列上的一段长度为\(2^{\lfloor\frac {8I}n\rfloor}\)的区间。

那么我们枚举区间左端点,双指针维护区间右端点,就可以求出答案了。

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 400000
#define INF 1e9
#define Gmin(x,y) (x>(y)&&(x=(y)))
using namespace std;
int n,m,t,a[N+5],s[N+5];
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define tn (x<<3)+(x<<1)
#define D isdigit(c=tc())
char c,*A,*B,FI[FS];
public:
I FastIO() {A=B=FI;}
Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
}F;
int main()
{
RI i,p1,p2,ans=INF;for(F.read(n,m),i=1;i<=n;++i) F.read(a[i]);//读入
for(sort(a+1,a+n+1),i=1;i<=n;++i) s[i]=a[i];t=unique(s+1,s+n+1)-s-1;//排序+离散化
if(m=8*m/n,m>=30) return puts("0"),0;if(m=(1LL<<m),m>t) return puts("0"),0;//若能选择的区间长度超过总长度,直接输出0
for(p1=p2=i=1;i+m-1<=t;++i)//枚举左端点
{
W(p1^n&&a[p1]<s[i]) ++p1;W(p2^n&&a[p2+1]<=s[i+m-1]) ++p2;//双指针维护原序列上的区间
Gmin(ans,(p1-1)+(n-p2));//更新答案
}return printf("%d",ans),0;//输出答案
}

\(B\):Welfare State(点此看题面)

大致题意: 支持两种操作,单点修改,全序列对一个数取\(Max\),求最后的序列。

我写了一个线段树。

我们用\(Mx_{rt}\)表明\(rt\)子树内所有数都要向它取\(Max\),然后当要对\(rt\)子树内的值进行单点修改时,就把\(Mx_{rt}\)下传给左右儿子。

最后每个位置的答案就是其在线段树中对应的叶节点的值与其到根路径上所有\(Mx_{rt}\)的最大值。

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200000
using namespace std;
int n,a[N+5];
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define pc(c) (C==E&&(clear(),0),*C++=c)
#define tn (x<<3)+(x<<1)
#define D isdigit(c=tc())
int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
public:
I FastIO() {A=B=FI,C=FO,E=FO+FS;}
Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
Tp I void write(Con Ty& x,Con char& y) {write(x),pc(y);}
I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
template<int SZ> class SegmentTree//线段树
{
private:
#define LT l,mid,rt<<1
#define RT mid+1,r,rt<<1|1
#define PD(x) (U(x<<1,Mx[x]),U(x<<1|1,Mx[x]),Mx[x]=0)
#define U(x,v) (Mx[x]<(v)&&(Mx[x]=v))
int n,V[SZ+5],Mx[SZ<<2];
I void Upt(CI x,CI y,CI l,CI r,CI rt)//单点修改
{
if(l==r) return (void)(Mx[rt]=0);RI mid=l+r>>1;PD(rt),
x<=mid?Upt(x,y,LT):Upt(x,y,RT);
}
I int Qry(CI x,CI l,CI r,CI rt)//单点查询
{
if(l==r) return max(V[l],Mx[rt]);RI mid=l+r>>1,t;
return t=x<=mid?Qry(x,LT):Qry(x,RT),max(t,Mx[rt]);
}
public:
I void Build(CI _n,int *a) {n=_n;for(RI i=1;i<=n;++i) V[i]=a[i];}
I void Upt(CI x,CI y) {V[x]=y,Upt(x,y,1,n,1);}I void Max(CI x) {U(1,x);}
I int Qry(CI x) {return Qry(x,1,n,1);}
};SegmentTree<N> S;
int main()
{
RI Qt,i,op,x,y;for(F.read(n),i=1;i<=n;++i) F.read(a[i]);S.Build(n,a);//初始化
F.read(Qt);W(Qt--) F.read(op,x),op==1?(F.read(y),S.Upt(x,y)):S.Max(x);//处理操作
for(i=1;i<=n;++i) F.write(S.Qry(i)," \n"[i==n]);return F.clear(),0;//输出序列
}

\(C\):Matching vs Independent Set(点此看题面)

大致题意: 给你一张\(3n\)个点和\(m\)条边的图,求一个\(n\)条边的匹配或\(n\)个点的独立集。

这题的做法很巧妙啊。

考虑我们先对每条边扫一遍,只要它的两个端点都未曾作为某个匹配的端点,就把这条边作为一个匹配。

然后,如果作为匹配的边数大于等于\(n\),就直接输出其中的\(n\)条边。

否则,作为匹配的点数显然小于\(2n\),也就是说,剩下的点数大于\(n\)。而剩下的点两两之间,显然都没有边相连,否则就会被抓去作为匹配。所以输出其中\(n\)个点即可。

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
#define M 500000
using namespace std;
int n,m,s[3*N+5],ans[M+5];
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define pc(c) (C==E&&(clear(),0),*C++=c)
#define tn (x<<3)+(x<<1)
#define D isdigit(c=tc())
int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
public:
I FastIO() {A=B=FI,C=FO,E=FO+FS;}
Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
Tp I void write(Con Ty& x,Con char& y) {write(x),pc(y);}
I void writes(Con string& s) {for(RI i=0,l=s.length();i^l;++i) pc(s[i]);}
I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
int main()
{
RI Tt,i,t,x,y;F.read(Tt);W(Tt--)
{
for(F.read(n,m),i=1;i<=3*n;++i) s[i]=0;//清空
for(t=0,i=1;i<=m;++i) F.read(x,y),!s[x]&&!s[y]&&(s[x]=s[y]=1,ans[++t]=i);//若能作为匹配就作为匹配
if(t>=n) for(F.writes("Matching\n"),i=1;i<=n;++i) F.write(ans[i]," \n"[i==n]);//若存在匹配
else for(F.writes("IndSet\n"),t=0,i=1;i<=3*n&&t^n;++i) !s[i]&&(F.write(i," \n"[++t==n]),0);//否则存在独立集
}return F.clear(),0;
}

\(D\):Rectangle Painting 1(点此看题面)

大致题意: 给你一个方阵,其中有一些格子被染黑,每次可以选择一个\(w*h\)的区间以\(max(w,h)\)的代价将其染黑,求最小代价将整个方阵染白。

\(n\)很小,想到暴力\(DP\)。

设\(f_{xx,yx,xy,yy}\)表示将以\((xx,yx)\)为左上角、\((xy,yy)\)为右下角的区间全染白的最小代价。

可以以\(dfs\)形式转移,每次枚举一行或一列,将这个区间分裂转移。

由于有记忆化,跑满也只是\(O(n^5)\)的。而且其中有些区间是不合法的,并且当一个区间全白或全黑的时候我们可以直接返回答案,所以跑不满,是能过的。

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 50
using namespace std;
int n,a[N+5][N+5],s[N+5][N+5],f[N+5][N+5][N+5][N+5];
I int DP(CI xx,CI yx,CI xy,CI yy)//求将当前区间染白的最小代价
{
if(f[xx][yx][xy][yy]) return f[xx][yx][xy][yy];RI i,t,res=max(xy-xx+1,yy-yx+1);//如果访问过
if(t=s[xy][yy]-s[xx-1][yy]-s[xy][yx-1]+s[xx-1][yx-1],!t) return 0;if(t==(xy-xx+1)*(yy-yx+1)) return res;//如果全白或全黑
for(i=xx;i^xy;++i) t=DP(xx,yx,i,yy)+DP(i+1,yx,xy,yy),res>t&&(res=t);//枚举一行分裂
for(i=yx;i^yy;++i) t=DP(xx,yx,xy,i)+DP(xx,i+1,xy,yy),res>t&&(res=t);return f[xx][yx][xy][yy]=res;//枚举一列分裂
}
int main()
{
RI i,j;string st;for(scanf("%d",&n),i=1;i<=n;++i)
for(cin>>st,j=1;j<=n;++j) a[i][j]=st[j-1]=='#',
s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+a[i][j];//预处理二维前缀和
return printf("%d",DP(1,1,n,n)),0;
}

\(E\):Rectangle Painting 2(点此看题面)

大致题意: 给你一个方阵,其中有一些区间被染黑,每次可以选择一个\(w*h\)的区间以\(min(w,h)\)的代价将其染黑,求最小代价将整个方阵染白。

由于是\(min(w,h)\),所以贪心考虑,我们每次必然染白一行或者一列。

这就变成了一个经典的二分图匹配问题。

我们对于黑色格子\((i,j)\),由第\(i\)行向第\(j\)列连一条容量为\(INF\)的边。

由超级源向每行连边,由每列向超级汇连边,然后跑最大流即可。

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define M 50
#define INF 2e9
using namespace std;
int n,m,xx[M+5],xy[M+5],yx[M+5],yy[M+5],v[2*M+5][2*M+5];
class Discretization//离散化
{
private:
int s[2*M+5];
public:
int n;I void Ins(CI x) {s[++n]=x;}I void Init() {sort(s+1,s+n+1),n=unique(s+1,s+n+1)-s-1;}
I int GV(CI x) {return lower_bound(s+1,s+n+1,x)-s;}I int GF(CI x) {return s[x];}
}Dx,Dy;
template<int PS,int ES> class Dinic//最大流
{
private:
#define Else(x) ((((x)-1)^1)+1)
#define add(x,y,f) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].F=f)
int ee,lnk[PS+5],cur[PS+5],q[PS+5],dep[PS+5];struct edge {int to,nxt,F;}e[2*ES+5];
I bool BFS(CI s,CI t)//BFS找增广路
{
RI i,k,H=1,T=0;for(i=1;i<=Dx.n+Dy.n+2;++i) dep[i]=0;dep[q[++T]=s]=1;
W(H<=T&&!dep[t]) for(i=lnk[k=q[H++]];i;i=e[i].nxt)
e[i].F&&!dep[e[i].to]&&(dep[q[++T]=e[i].to]=dep[k]+1);
return dep[t];
}
I int DFS(CI x,RI f)//DFS求最大流
{
if(x==T||!f) return f;RI& i=cur[x];RI t,res=0;for(;i;i=e[i].nxt)
{
if((dep[x]+1)^dep[e[i].to]||!e[i].F||!(t=DFS(e[i].to,min(f,e[i].F)))) continue;
if(e[i].F-=t,e[Else(i)].F+=t,res+=t,!(f-=t)) return res;
}return dep[x]=-1,res;
}
public:
int S,T;I Dinic() {S=1,T=2;}I int P1(CI x) {return x+2;}I int P2(CI x) {return x+Dx.n+2;}
I void Add(CI x,CI y,CI f) {add(x,y,f),add(y,x,0);}//连边
I void Solve()
{
RI i,f=0;W(BFS(S,T)) {for(i=1;i<=Dx.n+Dy.n+2;++i) cur[i]=lnk[i];f+=DFS(S,INF);}//最大流
printf("%d",f);//输出答案
}
};Dinic<4*M+2,4*M+4*M*M> D;
int main()
{
RI i,j,k;scanf("%d%d",&n,&m);
for(i=1;i<=m;++i) scanf("%d%d%d%d",xx+i,yx+i,xy+i,yy+i),//读入
Dx.Ins(xx[i]),Dx.Ins(++xy[i]),Dy.Ins(yx[i]),Dy.Ins(++yy[i]);
for(Dx.Ins(n+1),Dy.Ins(n+1),Dx.Init(),Dy.Init(),i=1;i<=m;++i)//对于每个黑色区间
{
xx[i]=Dx.GV(xx[i]),yx[i]=Dy.GV(yx[i]),xy[i]=Dx.GV(xy[i])-1,yy[i]=Dy.GV(yy[i])-1;//求出离散化后的值
for(j=xx[i];j<=xy[i];++j) for(k=yx[i];k<=yy[i];++k) ++v[j][k];//每行向每列连边
}
for(i=1;i^Dx.n;++i) for(j=1;j^Dy.n;++j) v[i][j]&&(D.Add(D.P1(i),D.P2(j),INF),0);//连边
for(i=1;i^Dx.n;++i) D.Add(D.S,D.P1(i),Dx.GF(i+1)-Dx.GF(i));
for(i=1;i^Dy.n;++i) D.Add(D.P2(i),D.T,Dy.GF(i+1)-Dy.GF(i));return D.Solve(),0;
}

\(F\):GCD Groups 2(点此看题面)

大致题意: 让你把一组数分成两组,使每组\(gcd\)都为\(1\)。

随机+卡时大法好。

我们每次随机一个排列,然后枚举每一个数。贪心地想,若这个数加到第一组内,能使第一组的\(gcd\)减少,我们就把这个数加到第一组中,否则加到第二组中。

最后看下是否两组\(gcd\)都为\(1\),若为\(1\),就可以直接输出当前方案了。

如果直到\(0.49\)秒都没有得出答案,就可以输出无解了。

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 100000
using namespace std;
int n,a[N+5],s[N+5],p[N+5];
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define pc(c) (C==E&&(clear(),0),*C++=c)
#define tn (x<<3)+(x<<1)
#define D isdigit(c=tc())
int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
public:
I FastIO() {A=B=FI,C=FO,E=FO+FS;}
Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
Tp I void write(Con Ty& x,Con char& y) {write(x),pc(y);}
I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
I int gcd(CI x,CI y) {return y?gcd(y,x%y):x;}
int main()
{
RI i,t,g1,g2;for(F.read(n),i=1;i<=n;++i) F.read(a[i]),s[i]=i;
W(1.0*clock()/CLOCKS_PER_SEC<=0.49)//卡时
{
random_shuffle(s+1,s+n+1),g1=a[s[1]],p[s[1]]=1,g2=a[s[2]],p[s[2]]=0;//随机排列
for(i=3;i<=n;++i) (t=gcd(g1,a[s[i]]))<g1?(g1=t,p[s[i]]=1):(g2=gcd(g2,a[s[i]]),p[s[i]]=0);//贪心分组
if(g1==1&&g2==1) {for(puts("YES"),i=1;i<=n;++i) F.write(p[i]+1,' ');return F.clear(),0;}//若合法直接输出
}return puts("NO"),0;//输出无解
}

【CodeForces】CodeForcesRound576 Div1 解题报告的更多相关文章

  1. 【CodeForces】CodeForcesRound594 Div1 解题报告

    点此进入比赛 \(A\):Ivan the Fool and the Probability Theory(点此看题面) 大致题意: 给一个\(n\times m\)的矩阵\(01\)染色,使得不存在 ...

  2. codeforces 31C Schedule 解题报告

    题目链接:http://codeforces.com/problemset/problem/31/C 题目意思:给出 n 个 lessons 你,每个lesson 有对应的 起始和结束时间.问通过删除 ...

  3. codeforces 499B.Lecture 解题报告

    题目链接:http://codeforces.com/problemset/problem/499/B 题目意思:给出两种语言下 m 个单词表(word1, word2)的一一对应,以及 profes ...

  4. codeforces 495C. Treasure 解题报告

    题目链接:http://codeforces.com/problemset/problem/495/C 题目意思:给出一串只有三种字符( ')','(' 和 '#')组成的字符串,每个位置的这个字符 ...

  5. codeforces 490B.Queue 解题报告

    题目链接:http://codeforces.com/problemset/problem/490/B 题目意思:给出每个人 i 站在他前面的人的编号 ai 和后面的人的编号 bi.注意,排在第一个位 ...

  6. CodeForces 166E -Tetrahedron解题报告

    这是本人写的第一次博客,学了半年的基础C语言,初学算法,若有错误还请指正. 题目链接:http://codeforces.com/contest/166/problem/E E. Tetrahedro ...

  7. codeforces 489A.SwapSort 解题报告

    题目链接:http://codeforces.com/problemset/problem/489/A 题目意思:给出一个 n 个无序的序列,问能通过两两交换,需要多少次使得整个序列最终呈现非递减形式 ...

  8. codeforces 485A.Factory 解题报告

    题目链接:http://codeforces.com/problemset/problem/485/A 题目意思:给出 a 和 m,a 表示第一日的details,要求该日结束时要多生产 a mod ...

  9. codeforces 483A. Counterexample 解题报告

    题目链接:http://codeforces.com/problemset/problem/483/A 题目意思:给出一个区间 [l, r],要从中找出a, b, c,需要满足 a, b 互质,b, ...

随机推荐

  1. 解决:Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?

    简单粗暴法 删除锁 $ sudo rm /var/cache/apt/archives/lock $ sudo rm /var/lib/dpkg/lock 如果还不行,重启虚拟机 $ reboot

  2. Eclipse优化之设置不自动弹出控制台和Server

    有时候Eclipse启动,控制台console不会自动跳出来,需要手工点击该选项卡才行, 按下面的设置,可以让它自动跳出来(或不跳出来): windows  ->   preferences   ...

  3. 第02组 Beta版本演示

    目录 1. 博客链接及组员信息(2分) 2. 贡献比例(3分) 3. GitHub 项目链接(1分) 4. 博客汇总(2分) 5. 燃尽图(3分) 6. 原计划.达成情况及原因分析(6分) 7. Be ...

  4. ASP.NET Core 中使用负载均衡时获取客户端 IP

    在使用负载均衡的情况下,通过 context.Connection.RemoteIpAddress 获取到的是负载均衡的 IP 地址,需要通过 X-Forwarded-For 请求头才能获取到客户端的 ...

  5. php逻辑运算符 异或

  6. 《细说PHP》第四版 样章 第18章 数据库抽象层PDO 8

    18.6.4  执行准备好的查询 当准备好查询并绑定了相应的参数后,就可以通过调用PDOStatement类对象中的execute()方法,反复执行在数据库缓存区准备好的语句了.在下面的示例中,向前面 ...

  7. WPF 解决多个TreeViewItem同时触发某事件的简单方法

    原理是: 因为是双击事件,也就是同时引发了选择事件,TreeViewItem的IsSelected为True.通过触发器设置某个属性为特殊值,然后在CS页面的双击事件方法内判断是否此值即可. xaml ...

  8. 【BZOJ1921】【CTSC2010】珠宝商(点分治,后缀自动机)

    [BZOJ1921][CTSC2010]珠宝商(点分治,后缀自动机) 题面 洛谷 BZOJ权限题 题解 如果要我们做暴力,显然可以以某个点为根节点,然后把子树\(dfs\)一遍,建出特征串的\(SAM ...

  9. oracle中decode函数用法及应用

    用法 1.decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值) 相当于if else 那种方式. 2.decode(字段或字段的运算,值1,值2,值3) 当字段或字段的运 ...

  10. mysql 常用命令行总结

    登录 mysql -h -u root -p 回车后输入密码,即可登录 直接进入某个库 -D 库名 mysql -h -u root -D account -p 列举数据库.表 show databa ...