AtCoder Grand Contest 008

A - Simple Calculator

翻译

有一个计算器,上面有一个显示按钮和两个其他的按钮。初始时,计算器上显示的数字是\(x\),现在想把这个数字给变成\(y\)。两个按钮的作用分别是让这个数加一和把这个数取反。问最少的按按钮的次数。

题解

神仙特判题,想清楚再写。

#include<iostream>
using namespace std;
int x,y,ans=2147483647;
int main()
{
cin>>x>>y;
if(x==y){puts("0");return 0;}
if(y>x)ans=min(y-x,abs(y+x)+1);
else ans=min(abs(x+y)+1,2+abs(x-y));
printf("%d\n",ans);
return 0;
}

B - Contiguous Repainting

翻译

有\(n\)个格子,每个格子上面都有一个数字,初始时所有格子都是黑色。每次可以选择连续的格子,把他们都染成黑色或者白色。最大化最终状态下黑格子上面的数字和。

题解

我们抛去一个长度为\(K\)的区间,那么显然的,除了这个区间之外的任何一个格子我们都能够控制它的颜色,而这个区间只能整体为白或者整体为黑,那么讨论一下即可。

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
#define MAX 101000
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;
}
ll ans,sum,s[MAX],ss[MAX];
int n,k,a[MAX];
int main()
{
n=read();k=read();
for(int i=1;i<=n;++i)a[i]=read();
for(int i=1;i<=n;++i)s[i]=s[i-1]+(a[i]>0?a[i]:0);
for(int i=1;i<=n;++i)ss[i]=ss[i-1]+a[i];
for(int i=1;i<=n-k+1;++i)
{
sum=s[i-1]+(s[n]-s[i+k-1]);
if(ss[i+k-1]-ss[i-1]>0)sum+=ss[i+k-1]-ss[i-1];
ans=max(ans,sum);
}
cout<<ans<<endl;
return 0;
}

C - Tetromino Tiling

翻译

有\(7\)种俄罗斯方块,你现在要用他们拼出一个\(2*k\)的矩形,最大化\(k\)。

每种方块可以旋转但是不能对称的翻转。(输出的是\(k/2\))

题解

\(C\)比\(B\)简单系列。

首先\(2*2\)的是无脑放。剩下的可以放进去的显然只有\(1*4\)和两个\(L\)型的。发现这三个的匹配方法有两个自己匹配和三个各一个拼在一起匹配,算一下即可。

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
ll ans;
int a[8];
int main()
{
for(int i=1;i<=7;++i)scanf("%d",&a[i]);
ans+=a[2];ans+=2*(a[1]>>1);ans+=2*(a[4]>>1);ans+=2*(a[5]>>1);
if((a[1]&1)&&(a[4]&1)&&(a[5]&1))ans+=3;
else if((a[1]&1)&&(a[4]&1)&&(!(a[5]&1))&&a[5])ans+=1;
else if((a[1]&1)&&(!(a[4]&1))&&(a[5]&1)&&a[4])ans+=1;
else if((!(a[1]&1))&&(a[4]&1)&&(a[5]&1)&&a[1])ans+=1;
cout<<ans<<endl;
return 0;
}

D - K-th K

翻译

给定一个长度为\(n\)的序列\(x\),构造一个长度为\(n*n\)的序列\(a\),保证\([1,n]\)中的每个数都恰好出现了\(n\)次,并且第\(i\)个\(i\)出现的位置是\(x[i]\)。

题解

我说前面几题里面最傻逼的就是\(D\)题?

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAX 505
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,pos=1,a[MAX*MAX],p[MAX],x[MAX];
bool vis[MAX];
bool cmp(int a,int b){return x[a]<x[b];}
int main()
{
n=read();
for(int i=1;i<=n;++i)x[i]=read(),a[x[i]]=i,p[i]=i;
sort(&p[1],&p[n+1],cmp);
for(int i=1;i<=n;++i)
{
int v=p[i];
for(int j=1;j<v;++j)
{
while(a[pos])++pos;
a[pos]=v;
}
if(pos>x[v]){puts("No");return 0;}
}
for(int i=1;i<=n;++i)
{
int v=p[i];
for(int j=1;j<=n-v;++j)
{
while(a[pos])++pos;
if(pos<x[v]){puts("No");return 0;}
a[pos]=v;
}
}
puts("Yes");
for(int i=1;i<=n*n;++i)printf("%d ",a[i]);puts("");
return 0;
}

E - Next or Nextnext

翻译

给定一个长度为\(n\)的序列\(a\)。求满足要么\(P_i=a_i\),要么\(P_{P_i}=a_i\)的排列\(P\)的个数。

题解

我们把所有的\(i\)向\(a_i\)连边,那么对于一个合法的\(P\),两点之间要么跳一步,要么跳两步。

那么我们考虑这两种跳法可以构成几种不同的情况(对于一个环考虑)。

  • 所有点都跳了一步。那么显然就是原图。
  • 所有点都跳了两部。那么如果当前的环是一个奇环,那么显然它跳完之后还是一个奇环,只不过是点的顺序改变了一下,即得到了一个同构的环。如果当前的环是一个偶环,那么他就被拆分成了两个小环。
  • 一部分是奇环,一部分是偶环。那么这样子会形成一个环,然后在它的外面形成了一些"脚",即连进来的一些边。同时所有的"脚"都不会从同一个节点伸展出来,并且所有的脚都是一条链的形式。

把\(i\)连向\(a_i\)构成的图称之为原图,\(P\)构建出来的图称为新图,显然原图是由若干个部分组成的。同理\(P\)构建出来的图也只能基于原图,通过上面三种情况(如果奇偶环分开考虑就是四种),归类之后只有两种情况,一种是环,另外一种是长出了"脚",即基环内向树,这些东西构成。

先考虑原图构成的环,对于每个环要么就是原图,要么对于奇环而言是同构的图,要么是通过偶环被拆分成了两个等大小的图。那么我们把所有等大小的环一起考虑,考虑所有的方案数。在合并两个等大小的环的时候注意一下有环大小种方法合并。

再考虑基环内向树的情况,显然两两之间不能合并,所以我们分开考虑每一个的答案。首先对于两条腿,我们最多只有两种方法将一条腿和环合并(这里画不了图,直接看\(atcoder\)上面的题解就有图)。现在考虑合并两条腿的情况,设\(l1\)为第二条腿的长度,\(l2\)是两条腿在挂在环上的那个点的之间的距离。如果\(l1\lt l2\),那么有\(2\)种方法合并进来,如果\(l1=l2\),那么只有一种方法,否则\(0\)种方法。

代码里面有注释。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define MOD 1000000007
#define MAX 100100
#define ll long long
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,ans=1;
int a[MAX],dg[MAX];
bool cir[MAX];
int col[MAX],foot[MAX],cnt[MAX];
int f[MAX];
int main()
{
n=read();
for(int i=1;i<=n;++i)a[i]=read(),++dg[a[i]];
for(int i=1;i<=n;++i)
{
if(col[i])continue;
int x=i;
for(;!col[x];x=a[x])col[x]=i;
if(col[x]!=i)continue;//circle with foot
for(;!cir[x];x=a[x])cir[x]=true;//circle
}
for(int i=1;i<=n;++i)//illegal part
if((cir[i]&&dg[i]>2)||(!cir[i]&&dg[i]>1)){puts("0");return 0;}
for(int i=1;i<=n;++i)
{
if(dg[i])continue;//start of a foot do not have egde in
int x=i,len=0;
while(!cir[x])x=a[x],++len;
foot[x]=len;//record length
}
for(int i=1;i<=n;++i)//calculate answer of circle with feet
{
if(!cir[i])continue;//calculate circles
int x=i,pts=0,st=0,l1=0,fr=0;
//st:last root of foot,fr:first root of foot,l1:length of the first foot
//pts:number of the node in the circle
while(cir[x])
{
++pts;cir[x]=false;
if(foot[x])//a foot in the circle
{
if(!fr)st=fr=pts,l1=foot[x];
else
{
int ways=(foot[x]<(pts-st))+(foot[x]<=(pts-st));
ans=ans*ways%MOD;st=pts;
}
}
x=a[x];
}
if(fr)//first foot of the circle
{
int ways=(l1<(pts+fr-st))+(l1<=(pts+fr-st));
ans=ans*ways%MOD;
}
else//just a circle
cnt[pts]+=1;
}
for(int i=1;i<=n;++i)//dp,in order to calc each length of circles
{
if(!cnt[i])continue;
f[0]=1;
for(int j=1;j<=cnt[i];++j)
{
if(i>1&&(i&1))//odd circle
f[j]=(f[j-1]<<1)%MOD;//two ways
else//even circle
f[j]=f[j-1];//only one way
if(j>1)f[j]=(f[j]+1ll*f[j-2]*(j-1)%MOD*i%MOD)%MOD;
//merge two circle in the same length
}
ans=1ll*ans*f[cnt[i]]%MOD;
}
printf("%d\n",ans);
return 0;
}

F - Black Radius

题面

给定一个\(n\)个节点的树。有些点可以染色,每次染色操作为选定一个可以染色的点,以及一个距离,把距离这个点不超过钦定值的所有点全部染黑。初始时所有点都是白色。恰好可以进行一次染色,求最终所有点染色情况的方案数。

题解

抄题解.jpg。

定义\(f(x,d)\)表示距离\(x\)不超过\(d\)的点集。显然答案就是询问本质不同的\(f(x,d)\)的个数。考虑\(S=f(x,d1)=f(y,d_2)\),那么对于\(x\)到\(y\)路径上的任何一点\(K\),都有\(S=f(K,d_1-dist(x,K))\)。

我们现在在假设所有点都可以染黑的情况下来讨论答案。首先\(f(x,d)\)不考虑全集,最后再把全集加入答案即可。另外,对于\(x\)的任意一个相邻节点\(v\),不存在\(f(x,d)=f(v,d-1)\)。第一个限制很容易理解。考虑如何理解第二个限制,根据上面那个有关于两者等价的式子,需要满足路径上任意两点都等于当前点集,那么,当不存在相邻点\(v\)满足\(f(x,d)=f(v,d-1)\)的时候,证明\(x\)一定在这条路径的中点,因此也只会被考虑计算一次。

满足第一个限制的\(d\)的范围很好计算,只需要求出距离当前点的最远点即可。考虑第二个限制如何计算。想清楚什么时候会有\(f(x,d)=f(v,d-1)\)。如果以\(x\)为根,考虑距离\(v\)不超过\(d-1\)的所有点,如果除\(v\)自己的子树之外,所有\(x\)的子树都被染黑了,那么此时等式成立。那么在第二个限制中,\(d\)的范围是什么呢?显然不能超过到达它自己子树的最远距离。

这样只考虑了\(d\)的上界,而在一个点可以被染黑的时候,显然\(d\)的下界是\(0\)。现在考虑\(d\)不能被染黑时它的下界。我们先钦定\(x\)作为当前的树根。如果\(f(x,d)\)合法的话,必定满足一个可以被染黑的节点它的整棵子树都被染黑了,那么这里的下界就是这个可以被染黑的子树的最大深度。

然而我也不太懂(抄题解)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 200100
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;
}
const int inf=1e9;
struct Line{int v,next;}e[MAX<<1];
int h[MAX],cnt=1,dg[MAX];
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;++dg[u];}
int n,c[MAX],fa[MAX],sz[MAX];ll ans;
int S[MAX],top;
char s[MAX];
int d1[MAX];//子树中距离最远的一个点
int d2[MAX];//同上,可以从父亲转移
int d3[MAX];//子树中有经过至少一个黑点的最远点
int d5[MAX];//上界
int d6[MAX];//下界
void dfs1(int u,int ff)
{
fa[u]=ff;sz[u]=c[u];
if((u!=1&&dg[u]==1)||(u==1&&!dg[u]))//叶子节点
{
d1[u]=0;d3[u]=c[u]?0:inf;
return;
}
int mx=0,mx2=inf;
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(v==ff)continue;
dfs1(v,u);sz[u]+=sz[v];
mx=max(mx,d1[v]);
if(d3[v]<inf)mx2=min(mx2,d1[v]);
}
d1[u]=mx+1;d3[u]=mx2+1;
if(c[u])d3[u]=min(d3[u],d1[u]);
}
void dfs2(int u,int ff)
{
d2[u]=max(d2[u],(ff!=0)+d2[ff]);//从父亲转移过来
if(ff)d5[u]=max(d5[u],d2[u]-1);//维护上界
top=0;for(int i=h[u];i;i=e[i].next)if(e[i].v!=ff)S[++top]=e[i].v;
for(int i=1,mx=-1;i<=top;++i)//前缀其他儿子转移一下
{
int v=S[i];
d2[v]=max(d2[v],mx+2);
mx=max(mx,d1[v]);
}
for(int i=top,mx=-1;i>=1;--i)//后缀其他儿子转移一下
{
int v=S[i];
d2[v]=max(d2[v],mx+2);
mx=max(mx,d1[v]);
}
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)dfs2(e[i].v,u);
}
int main()
{
n=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read();
Add(u,v);Add(v,u);
}
scanf("%s",s+1);int tot=0;
for(int i=1;i<=n;++i)tot+=(c[i]=s[i]-48);
if(!tot){puts("0");return 0;}
memset(d3,63,sizeof(d3));
dfs1(1,0);dfs2(1,0);
for(int i=1;i<=n;++i)
{
if(c[i])d6[i]=0;//可以涂色的点
else d6[i]=min(d3[i],(sz[i]==sz[1])?inf:d2[i]);
//不能涂色的点考虑下界
int u=max(d1[i],d2[i])-1;//u为上界,初始为最短点距离减一
for(int j=h[i];j;j=e[j].next)
{
int v=e[j].v;
if(v==fa[i])u=min(u,d1[i]+1);//如果从父亲转移过来,
else u=min(u,d5[v]+1);
}
if(u>=d6[i])ans+=u-d6[i]+1;
}
cout<<ans+1<<endl;
return 0;
}

AtCoder Grand Contest 008的更多相关文章

  1. AtCoder Grand Contest 008 D - K-th K

    题目传送门:https://agc008.contest.atcoder.jp/tasks/agc008_d 题目大意: 给你一个长度为\(N\)的序列\(A\),请你构造一个长度为\(N^2\)的序 ...

  2. Atcoder Grand Contest 008 E - Next or Nextnext(乱搞+找性质)

    Atcoder 题面传送门 & 洛谷题面传送门 震惊,我竟然能独立切掉 AGC E 难度的思维题! hb:nb tea 一道 感觉此题就是找性质,找性质,再找性质( 首先看到排列有关的问题,我 ...

  3. AtCoder Grand Contest 008 A

    Problem Statement Snuke has a calculator. It has a display and two buttons. Initially, the display s ...

  4. AtCoder Grand Contest 008题解

    传送门 \(A\) 分类讨论就行了 然而我竟然有一种讨论不动的感觉 int x,y; inline int min(R int x,R int y){return x<y?x:y;} inlin ...

  5. AtCoder Grand Contest 012

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

  6. AtCoder Grand Contest 011

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

  7. AtCoder Grand Contest 031 简要题解

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

  8. AtCoder Grand Contest 010

    AtCoder Grand Contest 010 A - Addition 翻译 黑板上写了\(n\)个正整数,每次会擦去两个奇偶性相同的数,然后把他们的和写会到黑板上,问最终能否只剩下一个数. 题 ...

  9. AtCoder Grand Contest 009

    AtCoder Grand Contest 009 A - Multiple Array 翻译 见洛谷 题解 从后往前考虑. #include<iostream> #include< ...

随机推荐

  1. 使用target打开的iframe 获取src的问题

    <a target="mainframe"href="xxx.jsp"/> <iframe id="mainframe" ...

  2. 20155234 Exp2 后门原理与实践

    Windows获得Linux Shell 1.查看ip 2.监听端口 3.实验成功如下图 Linux获得Win Shell 1.查看虚拟机ip 2.监听端口 3.实验成功如下图 使用NC传输数据 1. ...

  3. springmvc接收json注意事项

            在以前使用SpringMvc框架时,在接受json数据时碰到了一些奇怪的问题.这里记录下来,方便以后查阅. 1. data 里写json对象 , 即该json数据没有被单(双)引号包住 ...

  4. 欧几里得算法(及扩展)&&快速幂(二分+位运算)

    最近在二中苦逼地上课,天天听数论(当然听不懂) 但是,简单的还是懂一点的 1.欧几里得算法 说得这么高级干什么,gcd入门一个月的人都会吧,还需要BB? 证明可参照其他博客(不会),主要就是gcd(a ...

  5. 论FPGA建模,与面向对象编程的相似性

    很久没有写FPGA方面的博客了,因为最近一直在弄一个绘图的上位机. 我觉得自己建模思想还不错,但是面向对象思维总是晕的.突然有一天发现,两者居然有这么对共同之处,完全可以相互启发啊.就简单聊下. 1. ...

  6. debian系统下改语言设置

    debian系统下改语言设置 安装debian 的时候选择了中文zh_CN_UTF-8,然后进系统后想换成en_US_UTF-8 可以使用一下命令选择:找到需要的语言 确定即可 dpkg-reconf ...

  7. STM32一键下载电路设计原理

    先放原理图(补充:图中的BOOT0通过10K的电阻接到地),再解释为什么这么设计: STM32启动方式:BOOT0和 BOOT1用于设置 STM32的启动方式 ,见下表: BOOT0=1,BOOT1= ...

  8. VMware桥接模式连接局域网

    今天尝试虚拟机直连家里的局域网,用于方便另外一台主机使用家里的虚拟机. 本次连接方式是通过桥接方式,但由于'桥接到'选项默认自动,导致无法连通,最终以下步骤完成配置: 第一步:确认本地网关地址 第二步 ...

  9. Tengine 添加第三方监控模块nginx-module-vts

    一.概述 除nginx官网源码提供的各种模板,nginx还有第三方模块.官方文档中也列出了nginx的很多第三方模块,除官网之外,还有很多的有用的模块也能在Github上找到. 官网第三方模块地址:h ...

  10. python语言程序设计2

    1, 代码高亮色彩体系 2, 缩进,一行代码开始前的空白区域,表达程序的格式框架 单层缩进,多层缩进 特点 概念,缩进是语法的一部分,缩进不正确的话可能会导致程序运行错误 用处(意义),是表达代码间包 ...