当前位置: 首页 > news >正文

Codeforces Round 1046 (Div. 1)

Preface

抛开整个八月完全没写代码不谈,就 CF 来说感觉已经有一万年没打了

由于 NJU CS 预推免有机试,想着恢复下手感就现场打了这场,没想到 2h Div1 能出四题

看来摆烂确实有助于水平提高啊,这下不得不多摆烂会了


A. Against the Difference

直接 DP,令 \(f_i\) 表示前 \(i\) 个位置的答案,钦定 \(f_i\) 不降

转移的话就是找到最靠右的位置 \(j\),满足 \([j,i]\) 中当前的数 \(a_i\) 出现次数恰为 \(a_i\) 次,拿个 vector 随便维护即可

#include<cstdio>
#include<iostream>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005;
int t,n,a[N],f[N],num[N]; vector <int> pos[N];
int main()
{for (scanf("%d",&t);t;--t){scanf("%d",&n);for (RI i=1;i<=n;++i) pos[i].clear();for (RI i=1;i<=n;++i){scanf("%d",&a[i]);pos[a[i]].push_back(i);num[i]=(int)pos[a[i]].size();}for (RI i=1;i<=n;++i){f[i]=f[i-1];if (num[i]<a[i]) continue;f[i]=max(f[i],f[pos[a[i]][num[i]-a[i]]-1]+a[i]);}printf("%d\n",f[n]);}return 0;
}

B. For the Champion

思博题

考虑先用 4 次操作,即 \(x,y\) 各加两次 \(10^9\),把当前位置移动到所有点的右上方,此时可以列出关于 \(X+Y\) 的一个方程

然后再用 4 次操作,即将 \(y\) 减去四次 \(10^9\),把当前位置移动到所有点的右下方,此时可以列出关于 \(X-Y\) 的一个方程

联立即可得到 \(X,Y\) 的值

#include<cstdio>
#include<iostream>
#include<vector>
#define int long long
#define RI register int
#define CI const int&
using namespace std;
const int N=105,LEN=1e9;
int t,n;
signed main()
{for (scanf("%lld",&t);t;--t){scanf("%lld",&n);int xpy_max=-1e18,ymx_min=1e18;for (RI i=1;i<=n;++i){int x,y; scanf("%lld%lld",&x,&y);xpy_max=max(xpy_max,x+y);ymx_min=min(ymx_min,y-x);}int tmp,A,B;printf("? R %lld\n",LEN);fflush(stdout); scanf("%lld",&tmp);printf("? R %lld\n",LEN);fflush(stdout); scanf("%lld",&tmp);printf("? U %lld\n",LEN);fflush(stdout); scanf("%lld",&tmp);printf("? U %lld\n",LEN);fflush(stdout); scanf("%lld",&A);printf("? D %lld\n",LEN);fflush(stdout); scanf("%lld",&tmp);printf("? D %lld\n",LEN);fflush(stdout); scanf("%lld",&tmp);printf("? D %lld\n",LEN);fflush(stdout); scanf("%lld",&tmp);printf("? D %lld\n",LEN);fflush(stdout); scanf("%lld",&B);A=A+xpy_max-4LL*LEN;B=B-ymx_min-4LL*LEN;int X=(A+B)/2,Y=(A-B)/2;printf("! %lld %lld\n",X,Y); fflush(stdout);}return 0;
}

C. By the Assignment

感觉很套路的一个题啊

简单手玩一下会发现题目的限制等价于:偶环上所有数都相同,奇环上所有数都必须为 \(0\)

因此可以考虑用并查集维护所有值一样的点以及它们对应的值

具体实现时,可以先求出原图的 DFS 生成树,此时所有非树边都是返祖边

加入一条非树边时,相当于将对应两点树上路径上的所有点连成一个集合,钦定并查集连边的方向后直接暴力的复杂度就是对的(因为最多合并 \(O(n)\)​ 次)

判掉无解的情况后,最后答案就是 \(V\) 的未确定的集合数量次方

当然这题也能用点双+染色来写,但感觉不如这种方法简单好写

#include<cstdio>
#include<iostream>
#include<vector>
#define RI register int
#define CI const int&
using namespace std;
const int N=200005,mod=998244353;
int t,n,m,V,vis[N],dep[N],anc[N],fa[N],val[N],flag;
vector <int> v[N]; vector <pair <int,int>> E;
inline void DFS(CI now,CI lst=-1)
{vis[now]=1;for (auto to:v[now]){if (vis[to]){if (to!=lst) E.push_back({now,to});continue;}anc[to]=now;dep[to]=dep[now]+1;DFS(to,now);}
}
inline int getfa(CI x)
{return x!=fa[x]?fa[x]=getfa(fa[x]):x;
}
inline int merge(CI a,CI b)
{if (a==-1&&b==-1) return -1;if (a==-1&&b!=-1) return b;if (a!=-1&&b==-1) return a;if (a==b) return a; else return flag=0,-1;
}
inline void link(int x,int y)
{x=getfa(x); y=getfa(y);fa[x]=y; val[y]=merge(val[x],val[y]);
}
int main()
{for (scanf("%d",&t);t;--t){scanf("%d%d%d",&n,&m,&V);for (RI i=1;i<=n;++i){scanf("%d",&val[i]);v[i].clear(); vis[i]=0;}for (RI i=1;i<=m;++i){int x,y; scanf("%d%d",&x,&y);v[x].push_back(y); v[y].push_back(x);}E.clear(); dep[1]=1; DFS(1); flag=1;for (RI i=1;i<=n;++i) fa[i]=i;for (auto [x,y]:E){int dlt=dep[y]-dep[x];while (getfa(x)!=getfa(y)){x=getfa(x);link(x,anc[x]);}if (dlt%2==0) val[getfa(y)]=merge(val[getfa(y)],0);}if (!flag) { puts("0"); continue; }int ans=1;for (RI i=1;i<=n;++i) vis[i]=0;for (RI i=1;i<=n;++i){int x=getfa(i);if (vis[x]) continue;vis[x]=1;if (val[x]==-1) ans=1LL*ans*V%mod;}printf("%d\n",ans);}return 0;
}

D1. From the Unknown (Easy Version)

挺有意思的一个题,D1 感觉还是很好想的

考虑先问 \(n\)\(1\),根据回答我们一定可以确定答案的一个可能范围 \(W\in [L,R]\)

通过打表不难发现 \(2L\ge R\) 始终成立,因此我们可以用如下方法进行第二次询问

\[L,1,L,2,L,3,\dots,L,R-L-1,L,R-L \]

不难发现一定存在一个分界点 \((L,M)\),使得它之前的相邻一对数分为一组,它之后的所有数单独分组

因此我们可以用 \(2\times (R-L)\) 的长度唯一确定 \(W\),最坏情况 \(L=50000,R=99999\),符合长度限制

#include<cstdio>
#include<iostream>
#include<vector>
#include<assert.h>
#define RI register int
#define CI const int&
using namespace std;
const int N=100000;
int t;
int main()
{/*int mxd=0,ml,mr;for (RI k=2;k<=100000;++k){int L=(n+k-1)/k,R=n/(k-1);while (R>=L&&(n+R-1)/R!=k) --R;if (L>R) continue;assert(2*L>=R);if (R-L>mxd) mxd=R-L,ml=L,mr=R;}printf("%d %d\n",ml,mr);*/for (scanf("%d",&t);t;--t){printf("? %d ",N);for (RI i=1;i<=N;++i)printf("1%c"," \n"[i==N]);fflush(stdout);int k; scanf("%d",&k);if (k==1){printf("! %d\n",N); fflush(stdout);continue;}int L=(N+k-1)/k,R=N/(k-1);while (R>=L&&(N+R-1)/R!=k) --R;if (L==R){printf("! %d\n",L); fflush(stdout);continue;}printf("? %d ",2*(R-L));for (RI i=R-L;i>=1;--i)printf("%d %d%c",L,i," \n"[i==1]);fflush(stdout); scanf("%d",&k);printf("! %d\n",R-(k-(R-L))); fflush(stdout);}return 0;
}

D2. From the Unknown (Hard Version)

其实比赛的时候 D2 的思路基本全出来了

但因为参数要写暴力找就偷懒没写(其实是太困了早早睡觉去了)

考虑第一次询问改为问 \(N\)\(B\),根据回答可以分为两种情况:

  • 回答为 \(0\),此时说明 \(W\in[1,B-1]\),不难发现第二次问 \(B^2\)\(1\) 就可以唯一确定 \(W\)
  • 回答不为 \(0\),此时可以解出 \(W\in \displaystyle \left[B\cdot \left(\left\lfloor\frac{N - 1}{r} + 1\right\rfloor \right), B\cdot \left(\left\lfloor\frac{N - 1}{r - 1} + 1\right\rfloor \right) - 1\right]=[L,R]\)

因此暴力枚举所有可能的 \(N,B\),使得 \(N+\max(B^2,2\times (R-L))\) 的值最小即可

\(N=11343,B=116\) 得到最大询问长度为 \(24799\le 25000\),可以通过

#include<cstdio>
#include<iostream>
#include<vector>
#include<assert.h>
#define RI register int
#define CI const int&
using namespace std;
const int N=11343,B=116;
int t;
int main()
{for (scanf("%d",&t);t;--t){printf("? %d ",N);for (RI i=1;i<=N;++i)printf("%d%c",B," \n"[i==N]);fflush(stdout);int k; scanf("%d",&k);if (k==0){printf("? %d ",B*B);for (RI i=1;i<=B*B;++i)printf("1%c"," \n"[i==B*B]);fflush(stdout); scanf("%d",&k);for (RI W=1;W<B;++W)if ((B*B+W-1)/W==k){printf("! %d\n",W); fflush(stdout);break;}} else{int L=-1,R=-1;for (RI W=B;W<=100000;++W)if ((N+(W/B)-1)/(W/B)==k){if (L==-1) L=W; R=W;}if (L==R){printf("! %d\n",L); fflush(stdout);continue;}printf("? %d ",2*(R-L));for (RI i=R-L;i>=1;--i)printf("%d %d%c",L,i," \n"[i==1]);fflush(stdout); scanf("%d",&k);printf("! %d\n",R-(k-(R-L))); fflush(stdout);}}return 0;
}

Postscript

最后事实证明打 CF 对 NJU 的机试也并没有什么太大的帮助

http://www.sczhlp.com/news/58901/

相关文章:

  • 网站建设公司业务员公众号运营收费价格表
  • 网站开发 -(广告)明天上海封控16个区
  • 项城网站制作多少钱自己怎样建设网站首页
  • 网站开发如何模块化九九建筑网登入
  • 简约网站模板网站开发下人员配置
  • 厦门网站建设推广贵阳软件制作
  • 网站建设市场调研报告做公司网站要营业执照吗
  • 中山网站建设网站鞍山网站
  • 免费建个人网站步骤网站禁用右键
  • 网站降权哪种网站名称容易通过备案审核
  • 深度学习中的数据类型介绍:FP32, FP16, TF32, BF16, Int16, Int8
  • 网站设计为什么学不好网页素材库
  • 东莞网站建设星河山东seo第一
  • 网站建设的技术有哪些公司名称变更网站要重新备案吗
  • 出售企业网站备案资料沂水网站建设
  • 比较好的前端网站微平台公众号
  • 阿里云建站wordpress有没有免费开网站的
  • 实战项目配置实验
  • pushgateway 使用
  • 做网站需不需要服务器组织建设是什么意思
  • 广州网站建设优化公司wordpress图片粘贴插件
  • 网站建设pdf下载遵义网吧什么时候恢复营业
  • 国外做黄漫的网站北京政平建设投资集团有限公司网站
  • 网站代理网站移动网站开发实例
  • 大连建设银行网站wordpress注册不发送邮件
  • 企业网站建设ppt公司网站百度搜索的描述怎么做
  • 某男神去年年底来某网站做见面会_竟要求安保人数超过两位数视频直播网站建设
  • linux命令 - Slayer
  • 货拉拉开源两款三方库,为鸿蒙应用高效开发贡献力量
  • javascript高级编程系列 - 前端开发中如何处理base64编码