Codeforces Round #576 (Div. 1)
Preface
闲来无事打打CF,就近找了场Div1打打
这场感觉偏简单,比赛时艹穿的人都不少,也没有3000+的题
两三个小时就搞完了吧(F用随机水过去了)
A. MP3
题意不好理解,没用翻译看了好久然后就看错了,后来发现是个SB题
考虑我们将数字排序+离散化之后就可以知道一个区间外有多少个数,可以直接计算答案
然后发现这个区间的移动有单调性,因此直接two points扫一下就好了
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=400005;
int n,lim,num,log_[N],a[N],rst[N],L[N],R[N],ans=1e9;
int main()
{
RI i,pos; for (scanf("%d%d",&n,&lim),lim*=8,i=1;i<=n;++i)
scanf("%d",&a[i]),rst[i]=a[i],log_[i]=ceil(log2(i));
sort(a+1,a+n+1); sort(rst+1,rst+n+1); num=unique(rst+1,rst+n+1)-rst-1;
for (i=1;i<=n;++i) R[a[i]=lower_bound(rst+1,rst+num+1,a[i])-rst]=i;
for (i=n;i;--i) L[a[i]]=i; for (i=pos=1;i<=num;++i)
{
while (pos<=i&&1LL*log_[i-pos+1]*n>lim) ++pos;
ans=min(ans,L[pos]-1+n-R[i]);
}
return printf("%d",ans),0;
}
B. Welfare State
题目大意就是单点修改和全局取\(\max\)(将所有数与一个数取\(\max\)),输出最后的序列
理解题意就很简单,我们记录下一个点最后一次被单点修改的值与时间,然后在所有全局取\(\max\)的操作中找一个时间在它后面的最大值尝试更新这个值即可
后缀\(\max\)+二分即可完成
#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
int n,x,q,opt,y,tim[N],lst[N],et[N],val[N],mx[N],tot;
int main()
{
//freopen("B.in","r",stdin); freopen("B.out","w",stdout);
RI i; for (scanf("%d",&n),i=1;i<=n;++i) scanf("%d",&lst[i]);
for (scanf("%d",&q),i=1;i<=q;++i)
{
scanf("%d%d",&opt,&x); if (opt^1) et[++tot]=i,val[tot]=x;
else scanf("%d",&y),tim[x]=i,lst[x]=y;
}
for (i=tot;i;--i) mx[i]=max(mx[i+1],val[i]); for (i=1;i<=n;++i)
printf("%d ",max(lst[i],mx[lower_bound(et+1,et+tot+1,tim[i])-et]));
return 0;
}
C. Matching vs Independent Set
思博题,我都想了些什么鬼东西啊
考虑那\(3n\)个点一定有着什么限制,那么我们考虑以下算法:
- 扫一遍所有边,若这条边的两个端点都没有被匹配过就匹配这条边,记此时匹配过的边数为\(cnt\)
- 若\(cnt\ge n\)则得出了一个合法匹配
- 否则在剩下的点中任取\(n\)个就是独立集
考虑这个算法的正确性,显然当\(cnt\ge n\)时能得出合法匹配,故若\(cnt<n\),则剩下的两两无边相连的点数就是\(3n-2\cdot cnt>n\),因此一定能得到答案
#include<cstdio>
#define RI register int
#define CI const int&
using namespace std;
const int N=3e5+5;
int t,n,m,x,y,eg[N],cnt; bool vis[N];
int main()
{
for (scanf("%d",&t);t;--t)
{
RI i; for (scanf("%d%d",&n,&m),cnt=0,i=1;i<=m;++i)
scanf("%d%d",&x,&y),!vis[x]&&!vis[y]&&(vis[x]=vis[y]=1,eg[++cnt]=i);
if (cnt>=n)
{
puts("Matching"); for (i=1;i<=n;++i)
printf("%d%c",eg[i]," \n"[i==cnt]);
} else
{
puts("IndSet"); for (cnt=0,i=1;i<=3*n&&cnt<n;++i)
if (!vis[i]) printf("%d ",i),++cnt; putchar('\n');
}
for (i=1;i<=3*n;++i) vis[i]=0;
}
return 0;
}
D. Rectangle Painting 1
首先我们考虑两个显而易见的结论:
- 若一个子矩阵全为白显然无需染色
- 若一个子矩阵全为黑直接染完是最优的(即拆成小块永远没有直接染优)
那么我们把这两种情况作为DP的终止条件就可以DP了,设\(f_{x1,y1,x2,y2}\)表示\((x1,y1)-(x2,y2)\)的子矩阵全部染白的最小代价,转移的之后考虑断开行或列分割成两个更小的矩阵转移即可
用记忆化搜索实现DP,二维前缀和处理下矩阵状态即可
#include<cstdio>
#include<cstring>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int N=55;
int n,pt[N][N],f[N][N][N][N]; char ch;
inline void get_char(char& ch)
{
while (isspace(ch=getchar()));
}
inline int getpt(CI x1,CI y1,CI x2,CI y2)
{
return pt[x2][y2]-pt[x2][y1-1]-pt[x1-1][y2]+pt[x1-1][y1-1];
}
inline int DP(CI x1,CI y1,CI x2,CI y2)
{
if (~f[x1][y1][x2][y2]) return f[x1][y1][x2][y2];
if (getpt(x1,y1,x2,y2)==(x2-x1+1)*(y2-y1+1))
return f[x1][y1][x2][y2]=max(x2-x1+1,y2-y1+1);
if (!getpt(x1,y1,x2,y2)) return f[x1][y1][x2][y2]=0;
RI i; int ret=max(x2-x1+1,y2-y1+1);
for (i=x1;i<x2;++i) ret=min(ret,DP(x1,y1,i,y2)+DP(i+1,y1,x2,y2));
for (i=y1;i<y2;++i) ret=min(ret,DP(x1,y1,x2,i)+DP(x1,i+1,x2,y2));
return f[x1][y1][x2][y2]=ret;
}
int main()
{
RI i,j; for (scanf("%d",&n),i=1;i<=n;++i) for (j=1;j<=n;++j)
get_char(ch),pt[i][j]=pt[i-1][j]+pt[i][j-1]-pt[i-1][j-1]+(ch=='#');
return memset(f,-1,sizeof(f)),printf("%d",DP(1,1,n,n)),0;
}
E. Rectangle Painting 2
和上面一题类似,只不过把数据范围加大了,然后代价变成了取\(\min\)
又有一个显而易见的结论此时每次选择的都是一整行或一整列,代价为\(1\)
因此我们考虑将每个黑点的行节点向列节点连一条流量为\(\infty\)的边,然后从源点向行节点连流量为\(1\)的边,从列节点向汇点连流量为\(1\)的边,这样整张图的最小割即为答案(至少要割去一个黑点的行或列节点)
但是现在黑点给出的是一个矩阵的形式,这也很简单,我们将区间化为左开右闭,然后离散化一下,建图的时候源点到行节点连接这一段经过行的数目,到汇点的同理
然后跑一下最大流就是答案
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=205,M=200005,INF=1e9;
int n,m,l1[N],r1[N],l2[N],r2[N],rstl[N],rstr[N],numl,numr;
struct edge
{
int to,nxt,v;
}e[M]; int head[N],cnt=1,s,t;
inline int findl(CI x)
{
return lower_bound(rstl+1,rstl+numl+1,x)-rstl;
}
inline int findr(CI x)
{
return lower_bound(rstr+1,rstr+numr+1,x)-rstr;
}
inline void addedge(CI x,CI y,CI v)
{
e[++cnt]=(edge){y,head[x],v}; head[x]=cnt;
e[++cnt]=(edge){x,head[y],0}; head[y]=cnt;
}
#define to e[i].to
class Network_Flow
{
private:
int q[N],dep[N],cur[N];
inline bool BFS(CI s,CI t)
{
RI H=0,T=1; memset(dep,0,t+1<<2); q[dep[s]=1]=s;
while (H<T)
{
int now=q[++H]; for (RI i=head[now];i;i=e[i].nxt)
if (e[i].v&&!dep[to]) dep[to]=dep[now]+1,q[++T]=to;
}
return dep[t];
}
inline int DFS(CI now,CI tar,int dis)
{
if (now==tar) return dis; int ret=0;
for (RI& i=cur[now];i;i=e[i].nxt)
if (e[i].v&&dep[to]==dep[now]+1)
{
int dist=DFS(to,tar,min(dis,e[i].v));
dis-=dist; ret+=dist; e[i].v-=dist; e[i^1].v+=dist;
}
if (ret) dep[now]=0; return ret;
}
public:
inline int Dinic(CI s,CI t,int ret=0)
{
while (BFS(s,t)) memcpy(cur,head,t+1<<2),ret+=DFS(s,t,INF); return ret;
}
}NF;
#undef to
int main()
{
RI i,j,k; for (scanf("%d%d",&n,&m),i=1;i<=m;++i)
scanf("%d%d%d%d",&l1[i],&r1[i],&l2[i],&r2[i]),
--l1[i],rstl[++numl]=l1[i],rstl[++numl]=l2[i],
--r1[i],rstr[++numr]=r1[i],rstr[++numr]=r2[i];
sort(rstl+1,rstl+numl+1); numl=unique(rstl+1,rstl+numl+1)-rstl-1;
sort(rstr+1,rstr+numr+1); numr=unique(rstr+1,rstr+numr+1)-rstr-1;
for (i=1;i<numl;++i) addedge(s,i,rstl[i+1]-rstl[i]);
for (t=numl+numr+1,i=1;i<numr;++i) addedge(numl+i,t,rstr[i+1]-rstr[i]);
for (i=1;i<=m;++i)
{
l1[i]=findl(l1[i]); r1[i]=findr(r1[i]);
l2[i]=findl(l2[i]); r2[i]=findr(r2[i]);
for (j=l1[i];j<l2[i];++j) for (k=r1[i];k<r2[i];++k)
addedge(j,numl+k,INF);
}
return printf("%d",NF.Dinic(s,t)),0;
}
F. GCD Groups 2
讲道理我并不知道这题正解是什么,当时开个玩笑写个随机就过了
考虑我们随机从未选取的数中选择一个数,如果这个数扔到第一个集合中可以使当前的\(\gcd\)变小就扔进去
然后剩下的数都放进第二个集合里,我们发现这样的正确性显然,因为加入的数越多\(\gcd\)一定不会变大
但是随机的正确率我并不会证,大致理解了一下就是要求一个集合内存在一个质因子能整除每个数\(\gcd\)才不为\(1\),由于数的分布比较均匀因此质因子分布也很均匀
所以我们直接随机做,然后卡时到\(0.45s\)的时候退出输\(NO\)即可
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<algorithm>
#define RI register int
#define CI const int&
using namespace std;
const int N=100005;
int n,p[N],a[N],g1,g2,tp; bool cs[N];
inline int gcd(CI n,CI m)
{
return m?gcd(m,n%m):n;
}
int main()
{
//freopen("F.in","r",stdin); freopen("F.out","w",stdout);
RI i; for (srand(20030909),scanf("%d",&n),i=1;i<=n;++i)
scanf("%d",&a[i]),p[i]=i; while (1.0*clock()/CLOCKS_PER_SEC<=0.45)
{
for (random_shuffle(p+1,p+n+1),g2=0,g1=a[p[1]],cs[p[1]]=1,i=2;i<=n;++i)
if (g1!=1&&(tp=gcd(g1,a[p[i]]))<g1) cs[p[i]]=1,g1=tp; else g2=gcd(g2,a[p[i]]);
if (g1==1&&g2==1)
{
for (puts("YES"),i=1;i<=n;++i) printf("%d ",cs[i]+1); exit(0);
}
for (i=1;i<=n;++i) cs[i]=0;
}
return puts("NO"),0;
}
Postscript
讲道理这场CF难度确实不大,不过也算是有挺多思维好题的吧
今后得多做做这样的比赛QWQ
Codeforces Round #576 (Div. 1)的更多相关文章
- Codeforces Round #576 (Div. 2) D. Welfare State
http://codeforces.com/contest/1199/problem/D Examples input1 output1 input2 output2 Note In the firs ...
- Codeforces Round #576 (div.1 + div.2)
Div2 A 长度为\(n(n≤10^5)\)的数组,每个元素不同,求有多少个位置\(d\)满足\(d - x \le j < d \And d < j \le d + y a_d< ...
- Codeforces Round #576 (Div. 1) 简要题解 (CDEF)
1198 C Matching vs Independent Set 大意: 给定$3n$个点的无向图, 求构造$n$条边的匹配, 或$n$个点的独立集. 假设已经构造出$x$条边的匹配, 那么剩余$ ...
- Codeforces Round #576 (Div. 2) 题解
比赛链接:https://codeforc.es/contest/1199 A. City Day 题意:给出一个数列,和俩个整数\(x,y\),要求找到序号最靠前的数字\(d\),使得\(d\)满足 ...
- [快速幂]Codeforces Round #576 (Div. 2)-C. MP3
C. MP3 time limit per test 1 second memory limit per test 256 megabytes input standard input output ...
- Codeforces Round #366 (Div. 2) ABC
Codeforces Round #366 (Div. 2) A I hate that I love that I hate it水题 #I hate that I love that I hate ...
- Codeforces Round #354 (Div. 2) ABCD
Codeforces Round #354 (Div. 2) Problems # Name A Nicholas and Permutation standard input/out ...
- Codeforces Round #368 (Div. 2)
直达–>Codeforces Round #368 (Div. 2) A Brain’s Photos 给你一个NxM的矩阵,一个字母代表一种颜色,如果有”C”,”M”,”Y”三种中任意一种就输 ...
- cf之路,1,Codeforces Round #345 (Div. 2)
cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅..... ...
随机推荐
- LeetCode 150:逆波兰表达式求值 Evaluate Reverse Polish Notation
题目: 根据逆波兰表示法,求表达式的值. 有效的运算符包括 +, -, *, / .每个运算对象可以是整数,也可以是另一个逆波兰表达式. Evaluate the value of an arithm ...
- python在字节流中对int24的转换
python在字节流中对int24的转换 概述 最近在写项目的过程中,需要对从串口中读取的数据进行处理,本来用C写完了,但是却一直拿不到正确的数据包,可能是因为自己太菜了.后来用了python重新写了 ...
- Gin框架 - 数据绑定和验证
概述 上篇文章分享了 Gin 框架使用 Logrus 进行日志记录,这篇文章分享 Gin 框架的数据绑定与验证. 有读者咨询我一个问题,如何让框架的运行日志不输出控制台? 解决方案: engine : ...
- redis命令之 ----String(字符串)
SET SET key value [EX seconds] [PX milliseconds] [NX|XX] 将字符串值 value 关联到 key . 如果 key 已经持有其他值, SET 就 ...
- linux安装redis步骤
1.安装gcc redis是c语言编写的 -- 安装命令 yum install gcc-c++ -- 检查gcc 是否安装 gcc -v 2.下载redis安装包,在root目录下执行 wget ...
- 关于 Paket
参考地址:https://fsprojects.github.io/Paket/editor-support.html 1. 安装 Paket for Visual Studio,一个类似于 Nuge ...
- WPF 通过Win32SDK修改窗口样式
使用函数为 SetWindowLong GetWindowLong 注册函数 [DllImport("user32.dll", EntryPoint = "GetWind ...
- 【redis】redis异常-MISCONF Redis is configured to save RDB snapshots
使用redis报错: MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persis ...
- C# Random
一.简介 在Random类用于创建随机数.(当然是伪随机的.) 二.Random用法 例: Random rnd = new Random(); int month = rnd.Next(1, 13) ...
- java 线程之线程状态
Thread 类中的线程状态: public enum State { NEW,//新建 RUNNABLE,// 执行态 BLOCKED, //等待锁(在获取锁的池子里) WAITING,//等待状态 ...