AtCoder Grand Contest 006

吐槽

这套题要改个名字,叫神仙结论题大赛

A - Prefix and Suffix

翻译

给定两个串,求满足前缀是\(S\),后缀是\(T\),并且长度至少为\(n\)的最短串串长。

题解

暴力枚举\(S\)和\(T\)的重叠部分长度,然后直接\(check\)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAX 105
int n,l1,l2,ans=1e9;
char S[MAX],T[MAX];
bool check(int l)
{
for(int i=l1-l+1,j=1,k=1;k<=l;++k,++i,++j)
if(S[i]!=T[j])return false;
return true;
}
int main()
{
scanf("%d",&n);scanf("%s",S+1);scanf("%s",T+1);
l1=strlen(S+1);l2=strlen(T+1);
for(int l=0;l1+l2-l>=n&&l<=l1&&l<=l2;++l)
if(check(l))ans=min(ans,l1+l2-l);
printf("%d\n",ans);
return 0;
}

B - Median Pyramid Easy

翻译

给定一个塔状结构,从上往下的第\(i\)层有\(2i-1\)个位置。在最底层有一个\((2n-1)\)的排列,然后往上的每一个格子都等于正下方,左下方,右下方三个数中第二大的那个。

显然已知顶端的数,构造一个满足条件的排列。无解输出"No"

题解

不会啊,\(B\)题就这么难,身败名裂。大概就是把要的数放在中间,然后让它到达上一层的个数最多,剩下的空位置按照顺序搞就行了。

#include<iostream>
#include<cstdio>
using namespace std;
int n,x,a[200200];
bool vis[200200];
int main()
{
cin>>n>>x;int m=n+n-1;
if(x==1||x==n+n-1){puts("No");return 0;}
a[(m+1)>>1]=x;a[m>>1]=x-1;a[(m>>1)+2]=x+1;
vis[x]=vis[x-1]=vis[x+1]=true;
if(m/2>1&&x+2<=m)a[m/2-1]=x+2,vis[x+2]=true;
if(m/2+3<=m&&x>=3)a[m/2+3]=x-2,vis[x-2]=true;
for(int i=1,p=1;i<=m;++i)
{
if(a[i])continue;
while(vis[p])++p;
a[i]=p;vis[p]=true;
}
puts("Yes");
for(int i=1;i<=m;++i)printf("%d\n",a[i]);
return 0;
}

C - Rabbit Exercise

翻译

数轴上有\(n\)个点,一开始第\(i\)个点在位置\(a_i\)。

现在按照次序进行\(m\)次操作,每次给定一个\(x\),然后从\(x-1\)和\(x+1\)两个点中等概率随机选择一个点,将\(x\)的坐标关于这个点对称。

这\(m\)次操作重复进行\(K\)轮,求最终每个点所在位置的期望。

题解

无论怎么样任何一个点每次操作一定是变成\(2a_{x-1}(a_{x+1})-a_x\)。设\(f_x\)表示\(x\)这个点当前的期望,假设当前点要进行依次变换,那么期望为\(\frac{1}{2}((2f_{x-1}-f_x)+(2f_{x+1}-f_x))=f_{x+1}+f_{x-1}-f_x\)。

好的,然后进行\(K\)轮就不会了。怎么办呢?(当然是点开题解了啊)。闲着无聊来差分一下(菊开:差分是人类智慧),设\(d_i=f_i-f_{i-1}\),那么执行完一次操作之后:\(d_i=(f_{i-1}+f_{i+1}-f_i)-f_{i-1}=f_{i+1}-f_i\),\(d_{i+1}=f_{i+1}-(f_{i-1}+f_{i+1}-f_i)=f_i-f_{i-1}\)。

好啊,一次操作等价于交换\(d_i,d_{i+1}\),那么我们只要记录一下做完一轮操作之后\(d_i\)都到哪里去了,然后就可以倍增了。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 100100
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,x[MAX],m,d[MAX],ans[MAX],tmp[MAX];ll K;
double a[MAX];
int main()
{
n=read();
for(int i=1;i<=n;++i)x[i]=read();
m=read();cin>>K;
for(int i=1;i<=n;++i)d[i]=i,ans[i]=i;
for(int i=1;i<=m;++i)
{
int x=read();
swap(d[x],d[x+1]);
}
while(K)
{
if(K&1)
{
for(int i=1;i<=n;++i)tmp[i]=ans[d[i]];
for(int i=1;i<=n;++i)ans[i]=tmp[i];
}
for(int i=1;i<=n;++i)tmp[i]=d[d[i]];
for(int i=1;i<=n;++i)d[i]=tmp[i];
K>>=1;
}
for(int i=1;i<=n;++i)a[i]=x[ans[i]]-x[ans[i]-1];
for(int i=1;i<=n;++i)printf("%.1lf\n",a[i]+=a[i-1]);
return 0;
}

D - Median Pyramid Hard

翻译

见洛谷

题解

一般这种比大小的题目,我们都可以二分答案,然后把所有比二分值小的设为\(0\),比二分值大的设为\(1\),然后再来考虑问题。

那么现在如果在最底层出现了两个连续的\(1\),那么它们的上面两个数字(如果存在)也必定是两个连续的\(1\),\(0\)同理。那么检查一下\(0\)还是\(1\)能够走到更上面就好了。否则没有出现任意两个连续的数字,那么必定和最底下那一行中奇数位置上\(01\)相同。

这种性质题还是要多手玩,要不然还真的想不到。而\(OI\)题目最重要的一点永远都是抓住题目的性质。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 100100
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,m;
int a[MAX<<1],b[MAX<<1];
bool check(int mid)
{
for(int i=1;i<=m;++i)b[i]=a[i]>=mid;
for(int i=0;i<n;++i)
{
if(b[n-i]==b[n-i-1])return b[n-i];
if(b[n+i]==b[n+i+1])return b[n+i];
}
return b[1];
}
int main()
{
n=read();m=n+n-1;
for(int i=1;i<=m;++i)a[i]=read();
int l=1,r=m,ret;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid))ret=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ret);
return 0;
}

E - Rotate 3x3

翻译

给定一个\(3*n\)的矩阵,每次可以将一个\(3*3\)的子矩阵旋转\(180\)°,初始状态下,第\(i\)行第\(j\)列填着\(3*(j-1)+i\),给定目标矩阵,问是否能够旋转得到。

题解

既然说了抓性质,那就来抓旋转的性质。首先发现第二行怎么换都在第二行,然后发现无论怎么换,一个数所在位置的列永远不会变化。还发现一列的三个数是不会变动的,并且每次交换必定使得两列反过来。首先\(check\)一下每列的数字是否合法。接下来按列考虑,首先我们发现是可以构造出直接翻转相隔为\(2\)的两列而不影响其他列的方法。分奇偶考虑,计算奇数和偶数列被翻转的列的个数,显然这个的奇偶性只会与相反的奇偶性下被列被交换的次数相关,举个例子,比如说当且要交换偶数两列,那么必定以一个奇数列为中心进行交换,而这个奇数列也会被翻转,反过来一样的。那么模拟一下交换的过程,最后判断奇偶性即可。

为什么我什么题都不会做啊,总是能想一个开头却做不出来

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 100100
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,a[4][MAX],b[4],c[MAX],t[2];
void WA(){puts("No");exit(0);}
int main()
{
n=read();
for(int i=1;i<=3;++i)
for(int j=1;j<=n;++j)
{
int p=read();
int x=(p-1)%3+1,y=(p+2)/3;
if((i==2&&x!=2)||(i!=2&&x==2))WA();
if((y&1)^(j&1))WA();
a[i][j]=p;
}
for(int j=1;j<=n;++j)
{
for(int i=1;i<=3;++i)b[i]=a[i][j];
int y=(b[1]+2)/3,x=3*y-3;
for(int i=1;i<=3;++i)if(b[i]!=x+i&&b[i]!=x+4-i)WA();
t[j&1]^=(a[1][j]>a[2][j]);c[j]=y;
}
for(int i=1;i<=n;++i)
{
while(c[i]!=i)
{
t[i&1^1]^=1;
swap(c[i],c[c[i]]);
}
}
if(t[0]||t[1])WA();
puts("Yes");return 0;
}

F - Blackout

翻译

给定一个\(n*n\)的网格图,有些格子是黑色的。如果\((x,y),(y,z)\)都是黑色的,那么\((y,x)\)也会被染黑,求最终黑格子数量。

题解

继续不会做系列

我唯一能够想到的就是网格图我们显然是存不下的,把它转化成图来考虑。于是题目变成了:给定一个\(n\)个点\(m\)条边的图,如果\(x\rightarrow y\),\(y\rightarrow z\)的边都存在,那么连边\(z\rightarrow x\),回答边的数量。

然后开始手动翻译题解。

首先,我们可以计算每一个弱联通块(把边看成无向边的联通块),那么答案显然就是所有弱联通块的答案的总和。我们先假定图是一个弱联通图。

考虑这样一种情况,我们把点依次标号,然后在\(i\)和\(i+1\)之间连边,那么如果\(s\)和\(t\)之间存在边\(s\rightarrow t\),那么当且仅当\(t\equiv s+1(mod\ 3)\)。具有一定启发意义,我们考虑在模\(3\)的意义下搞点事情。我们用\(A,B,C\)给所有点做标记,并且强制要求对于任意一条边,只可能是\(A\rightarrow B\),\(B\rightarrow C\),\(C\rightarrow A\)。这样标号的方式可能不存在,但是不难证明一旦存在合法的标号方案,那么标号的方法唯一(不考虑循环\(ABC\)的顺序)。你可以把整个图给\(dfs\)一遍,这样子可以得到唯一的染色方案,或者证明它不存在。

通过标号的结果,我们可以得到三种情况,给出每种情况下的结论,等下再给出证明。

  • 当标号存在,但是并没有用到所有的三种颜色,那么你无法在这个联通块中进行任何操作。
  • 当标号存在,并且所有的三种颜色都被用到,那么你可以把所有\(AB\)之间连边,\(BC\)之间连边,\(CA\)之间连边,并且只能连这些边。
  • 当标号方案不存在,你可以给任意一对点之间连边,包括自环。

利用结论,可以很容易的计算出答案,时间复杂度\(O(m)\)。代码如下,证明内容(当然是翻译的啊)在代码后面。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 100100
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Line{int v,next,w;}e[MAX<<1];
int h[MAX],cnt=1,dg[MAX];
inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
int n,m;ll ans;
int vis[MAX],f[3],edge,size;bool label;
void dfs(int u,int d)
{
vis[u]=d;f[d]+=1;++size;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(e[i].w==1)++edge;
if(vis[v]==-1)dfs(v,(d+e[i].w)%3);
else if(vis[v]!=(vis[u]+e[i].w)%3)label=false;
}
}
int main()
{
n=read();m=read();
for(int i=1;i<=m;++i)
{
int x=read(),y=read();
Add(x,y,1);Add(y,x,2);
}
memset(vis,-1,sizeof(vis));
for(int i=1;i<=n;++i)
if(vis[i]==-1)
{
label=true;f[0]=f[1]=f[2]=0;size=edge=0;dfs(i,0);
if(label)ans+=(!min(f[0],min(f[1],f[2])))?(edge):(1ll*f[0]*f[1]+1ll*f[1]*f[2]+1ll*f[2]*f[0]);
else ans+=1ll*size*size;
}
cout<<ans<<endl;
return 0;
}
  • 当标号存在,但是并没有用到所有的三种颜色,那么你无法在这个联通块中进行任何操作。

    如果存在边\((x,y)\)和\((y,z)\),那么必定意为这所有的三种颜色都会被用到。既然如此,那么意味着这里不存在上述的边,所以你不能连出任何一条新边。

  • 当标号存在,并且所有的三种颜色都被用到,那么你可以把所有\(AB\)之间连边,\(BC\)之间连边,\(CA\)之间连边,并且只能连这些边。

    必定存在若干形如\((x,y),(y,z)\)这样的边,我们不妨令\(x\)染\(A\),\(y\)染\(B\),\(z\)染\(C\)。我们可以看出所有新连的边加上原边会构成一个个三角形。举个例子,令\(v\)存在一条边\((v,x)\),那么必定存在边\((y,v)\),那么我们不难证明任意一个\(v\)一定和\(x,y,z\)三个点中的两个有直接的边相连。所以任意的\(A\)都会连出一条\(A\rightarrow B\),其他的边同理。

  • 当标号方案不存在,你可以给任意一对点之间连边,包括自环。

    我们证明至少会存在一个自环。既然标号方案不存在,那么必定存在一个环导致了矛盾,注意,这个环不一定是有向环。那么这个环至少存在两条边\((x,y)\),\((y,z)\),那么我们可以连上\((z,x)\),那么等价于我们看这个环的时候可以直接跳过\(y\)。既然原先的环会导出矛盾,那么当前这个环照样会导出矛盾,那么我们重复这个过程,就可以得到自环。而其他的边存在的原因和前面两个证明类似,不再重复证明。

AtCoder Grand Contest 006的更多相关文章

  1. AtCoder Grand Contest 006 C:Rabbit Exercise

    题目传送门:https://agc006.contest.atcoder.jp/tasks/agc006_c 题目翻译 数轴上有\(N\)只兔子,从\(1\)到\(N\)编号,每只兔子初始位置是\(x ...

  2. Atcoder Grand Contest 006 D - Median Pyramid Hard(二分+思维)

    Atcoder 题面传送门 & 洛谷题面传送门 u1s1 Atcoder 不少思维题是真的想不出来,尽管在 Atcoder 上难度并不高 二分答案(这我倒是想到了),检验最上面一层的数是否 \ ...

  3. AtCoder Grand Contest 006 (AGC006) C - Rabbit Exercise 概率期望

    原文链接https://www.cnblogs.com/zhouzhendong/p/AGC006C.html 题目传送门 - AGC006C 题意 有 $n$ 个兔子,从 $1$ 到 $n$ 编号, ...

  4. AtCoder Grand Contest 006 F - Blackout

    Description 在 \(n*n\) 的棋盘上给出 \(m\) 个黑点,若 \((x,y)\),\((y,z)\) 都是黑点,那么 \((z,x)\) 也会变成黑点,求最后黑点的数量 题面 So ...

  5. [Atcoder Grand Contest 006 F][AGC006F] Blackout [染色]

    题面 传送门 思路 首先,这个涂黑的方法我们来优化一下模型(毕竟当前这个放到矩形里面,你并看不出来什么规律qwq) 我们令每个行/列编号为一个点,令边(x,y)表示一条从x到y的有向边 那么显然只要有 ...

  6. AtCoder Grand Contest 006 题解

    传送门 \(A\) 咕咕 const int N=105; char s[N],t[N];int n; inline bool eq(R int k){fp(i,1,k)if(s[n-k+i]!=t[ ...

  7. AtCoder Grand Contest 012

    AtCoder Grand Contest 012 A - AtCoder Group Contest 翻译 有\(3n\)个人,每一个人有一个强大值(看我的假翻译),每三个人可以分成一组,一组的强大 ...

  8. AtCoder Grand Contest 011

    AtCoder Grand Contest 011 upd:这篇咕了好久,前面几题是三周以前写的... AtCoder Grand Contest 011 A - Airport Bus 翻译 有\( ...

  9. AtCoder Grand Contest 031 简要题解

    AtCoder Grand Contest 031 Atcoder A - Colorful Subsequence description 求\(s\)中本质不同子序列的个数模\(10^9+7\). ...

随机推荐

  1. 将jar文件加到Maven的local repository中

    对于Maven项目来说,日常使用的多数第三方java库文件都可以从Maven的Central Repository中自动下载,但是如果我们需要的jar文件不在Central Repository中,那 ...

  2. oracle10g安装在裸设备上

    参考了百度文库上的 <在​裸​设​备​上​面​安​装​o​r​a​c​l​e​1​0​g> 一文. 不过为了简单起见,我选择OS 为 Redhat AS 4.8 32位. 准备安装数据库为 ...

  3. vijos 1641 Vs Snowy

    代码: #include<set> #include<cstdio> #include<cstring> #include<iostream> #inc ...

  4. java File读取文件始终不存在的问题分析

    先上图: 如图,f1 始终能读到该文件,使用的是绝对路径 f2 却是相对路径. 感觉很奇怪,明明一模一样的代码为什么会产生不同的结果呢? 首先想到的是是不是有什么特殊字符.. 拿到notepad++中 ...

  5. Flutter - ListView禁止用户上下滑动

    ListView禁止用户上下滑动可以使用physics属性 physics: const NeverScrollableScrollPhysics()

  6. CentOS7安装OpenStack(Rocky版)-02.安装Keyston认证服务组件(控制节点)

    本文分享openstack的认证服务组件keystone --------------- 完美的分割线 ---------------- 2.0.keystone认证服务 1)用户与认证:用户权限与用 ...

  7. 二叉树 c++

    树 非空树 有一个(root)根节点r 其余节点可分为m个互不相交的有限集(子树)T1....Tm 具有n个节点的树,具有(n-1)条连接(指针域),需要构成结构体,尽可能减少空间域的浪费,使用儿子兄 ...

  8. Codejam Qualification Round 2019

    本渣清明节 闲里偷忙 做了一下codejam 水平不出意外的在投稿之后一落千丈 后两题的hidden test竟然都挂了 A. Foregone Solution 水题,稍微判断一下特殊情况(比如10 ...

  9. 1. Python3 环境搭建

    Python3 环境搭建 开门见山,其他关于Python发展史.语言类型.优缺点等等 可以自己去百度百度,这里就不多说了.其实基本想要学这门语言的时候,你已经了解差不多了!!! Python的运行环境 ...

  10. JAVA每日一旅

    1.关于final关键字 final修饰的成员变量为基本数据类型时,在赋值之后无法改变.当final修饰的成员变量为引用数据类型时,在赋值后其指向地址无法改变,但是对象内容还是可以改变的. final ...