AGC, 即 AtCoder Grand Contest 006, 是日本一个在线比赛网站的最高难度级别比赛。AGC 的比赛频率非常低,这也是保证了其题目质量之高。
经常有人“心血来潮,开了一套AGC”,然后发现各种不会做,“感觉智商被AGC摁在地上摩擦”
今天我们来看一套比较古老的 AGC ,AGC 006
A - Prefix and Suffix
这道题目还是送温暖的...
直接枚举长度从
到
最后的
为用第二个字符串填充,剩余空缺从前到后一次用第一个字符串填充
最后验证前
位是否满足第一个字符串即可
由于是从小到大枚举,枚举到可行直接输出答案即可
代码语言:javascript复制#include<bits/stdc .h>
#define LL long long
#define pii pair<int,int>
#define mp make_pair
using namespace std;
int n,m;
char s[110],t[110],p[210];
bool check(int x)
{
for (int i=1;i<=n;i )
if (s[i]!=p[i]) return false;
return true;
}
int main()
{
n=read(s),n=strlen(s 1);
m=read(t);int x=0;
for (int i=n;i<=n n;i )
{
for (int j=1;j<=i-n;j )
p[j]=s[j];
for (int j=1;j<=n;j )
p[(i-n) j]=t[j];
if (check(i)) {print(i),puts("");return 0;}
}
return 0;
}
B - Median Pyramid Easy
这道题目就比较有意思了
首先考虑不可行的情况,显然当
或
的时候是不可行的
因为每一次取的都是三个格子中的中位数,显然到第二行的时候,
或
就消失不见了,更高的行中不可能出现
然后考虑其余情况的构造方法
一种比较通用的构造方法是,最高行为
,我们使得下一行出现至少两个
即可,如下图所示

我们只要保证图中所有的红色格子都是
的话,最后一行一定是
那么,现在,我们只需要构造最后一行的四个格子,使得从第二行开始就在指定位置出现连续的两个
了
这样就比较思博了,
即可
但是我们发现,当
的时候,会有点问题,那么我们对
特判一下,构造
当然,构造的方法不唯一
最后注意特判
的情况,不过我这样构造的话,不会出现问题
代码语言:javascript复制#include<bits/stdc .h>
#define LL long long
#define pii pair<int,int>
#define mp make_pair
using namespace std;
int n,m,a[200010],b[200010];
int main()
{
read(n);read(m);
if (m==1 || m==2*n-1) puts("No");
else
{
puts("Yes");
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
if (m>2)
{
a[n-1]=m-1,a[n]=m,a[n 1]=m 1,a[n 2]=m-2;
b[m-2]=1,b[m-1]=1,b[m]=1,b[m 1]=1;
}
else
{
a[n-1]=m 1,a[n]=m,a[n 1]=m-1,a[n 2]=m 2;
b[m-1]=1,b[m]=1,b[m 1]=1,b[m 2]=1;
}
int x=1;
for (int i=1;i<n-1;i )
{
while (b[x]==1) x ;
a[i]=x;b[x]=1;
}
for (int i=n 3;i<=2*n-1;i )
{
while (b[x]==1) x ;
a[i]=x;b[x]=1;
}
for (int i=1;i<=2*n-1;i )
print(a[i]),puts("");
}
return 0;
}
C - Rabbit Exercise
这道期望题目一颗赛艇啊
首先考虑对称位置的处理,显然
关于
和
的对称位置分别是
和
考虑兔子
的期望
这样,我们似乎已经得到了
的算法
我们从几何角度来考虑一下这个操作

其实就是
相对于
和
的相对位置发生了变化,
在外面的情况也是如此
再一般的来说,就是
和
的值进行了交换
那么,我们考虑差分,这样,每一次的操作就是对两个数进行交换了
而交换操作是分组进行的,我们可以根据类似快速幂的方式,在
的时间内完成交换
那么总的复杂度就是
#include<bits/stdc .h>
#define LL long long
#define pii pair<int,int>
#define mp make_pair
using namespace std;
int n,m,a[200010],b[200010];
int main()
{
read(n);read(m);
if (m==1 || m==2*n-1) puts("No");
else
{
puts("Yes");
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
if (m>2)
{
a[n-1]=m-1,a[n]=m,a[n 1]=m 1,a[n 2]=m-2;
b[m-2]=1,b[m-1]=1,b[m]=1,b[m 1]=1;
}
else
{
a[n-1]=m 1,a[n]=m,a[n 1]=m-1,a[n 2]=m 2;
b[m-1]=1,b[m]=1,b[m 1]=1,b[m 2]=1;
}
int x=1;
for (int i=1;i<n-1;i )
{
while (b[x]==1) x ;
a[i]=x;b[x]=1;
}
for (int i=n 3;i<=2*n-1;i )
{
while (b[x]==1) x ;
a[i]=x;b[x]=1;
}
for (int i=1;i<=2*n-1;i )
print(a[i]),puts("");
}
return 0;
}
int n,m,a[100010],b[100010],ans[100010],c[100010];
LL K;
double x[100010],z[100010];
void Work(LL x)
{
for (;x;x>>=1)
{
if (x&1)
{
for (int i=1;i<n;i )
c[i]=ans[b[i]];
for (int i=1;i<n;i )
ans[i]=c[i];
}
for (int i=1;i<n;i )
c[i]=b[b[i]];
for (int i=1;i<n;i )
b[i]=c[i];
}
}
int main()
{
read(n);
int y;
for (int i=1;i<=n;i )
read(y),x[i]=(double)y;
read(m),read(K);
for (int i=1;i<=m;i )
read(a[i]);
for (int i=1;i<n;i )
b[i]=i,ans[i]=i;
for (int i=1;i<=m;i )
swap(b[a[i]],b[a[i]-1]);
Work(K);
z[1]=x[1];
for (int i=1;i<n;i )
z[i 1]=z[i] (x[ans[i] 1]-x[ans[i]]);
for (int i=1;i<=n;i )
printf("%0.10lfn",z[i]);
return 0;
}
D - Median Pyramid Hard
这道题目似乎是B题的SPJ啊.....
考虑二分答案,假设当前需要验证的答案为
,表示答案
是否成立
那么,根据最下面一行和
的关系,我们可以得到底层的
数列,
表示
我们现在得到了底层的
数列,而题目所给的条件,上一层的一格为
,当且仅当下一层与之对应的三个中至少有两个
现在,符合情况的话,那么就是顶层为
我们可以画画图来分析一下底层的情况,如何向上传导
我们可以发现,当出现连续的两个
的时候,他们所对应的的上面,全部为

那么,这样的情况如何向外拓展呢?
我们发现,当连续的两个
旁边出现隔着一个位置的
的是否,这个全是
的竖行,可以向着隔着一个位置的
的方向拓展一列

那么我们只需要正着反着,各扫一遍
这样一来,我们就可以在
的时间内验证答案了
还有一种比较特殊的情况是,底层不需要出现连续的两个

特判一下
总的时间复杂度是
#include<bits/stdc .h>
#define LL long long
#define pii pair<int,int>
#define mp make_pair
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
if (p1==p2) { p2=(p1=buf) fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
return *p1 ;
}
inline void read(int &x){
char c=nc();int b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10 c-'0',c=nc()); x*=b;
}
inline void read(LL &x){
char c=nc();LL b=1;
for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
for (x=0;c>='0' && c<='9';x=x*10 c-'0',c=nc()); x*=b;
}
inline int read(char *s)
{
char c=nc();int len=1;
for(;!(c>='a' && c<='z');c=nc()) if (c==EOF) return 0;
for(;(c>='a' && c<='z');s[len ]=c,c=nc());
s[len ]='