AtCoder Grand Contest 012

A - AtCoder Group Contest

翻译

有\(3n\)个人,每一个人有一个强大值(看我的假翻译),每三个人可以分成一组,一组的强大值定义为三个人中第二强的人的强大值。求\(n\)组最大的强大值之和。

题解

这。。。不是倒着选两个人,正着选一个人构成一组就好了嘛。。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#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,a[300100];ll ans;
int main()
{
n=read();
for(int i=1;i<=n*3;++i)a[i]=read();
sort(&a[1],&a[n+n+n+1]);
for(int i=n+n+n-1,j=1;j<=n;++j,i-=2)ans+=a[i];
cout<<ans<<endl;
return 0;
}

B - Splatter Painting

翻译

给你一张无向图,每次给定一个点\(u_i\),让你把距离这个点不超过\(d_i\)的所有点都染成颜色\(c_i\)。输出最终每个点的颜色。

题解

这种染色问题倒着做。对于每个点记录一个它染出去的最远距离,因为\(d\)很小,所以这个值最多被改变\(d\)次。那么暴力即可。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
#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;
}
struct Line{int v,next;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int n,m,col[MAX],dis[MAX];
int Q,U[MAX],D[MAX],C[MAX];
void BFS(int S,int d,int c)
{
if(dis[S]>=d)return;dis[S]=d;
queue<int> Q;Q.push(S);
while(!Q.empty())
{
int u=Q.front();Q.pop();
if(!col[u])col[u]=c;
if(!dis[u])continue;
for(int i=h[u];i;i=e[i].next)
if(dis[e[i].v]<dis[u]-1)
{
dis[e[i].v]=dis[u]-1;
Q.push(e[i].v);
}
}
}
int main()
{
n=read();m=read();
for(int i=1;i<=m;++i)
{
int u=read(),v=read();
Add(u,v);Add(v,u);
}
Q=read();memset(dis,-1,sizeof(dis));
for(int i=1;i<=Q;++i)U[i]=read(),D[i]=read(),C[i]=read();
for(int i=Q;i;--i)
BFS(U[i],D[i],C[i]);
for(int i=1;i<=n;++i)printf("%d\n",col[i]);
return 0;
}

C - Tautonym Puzzle

翻译

构造一个长度不超过\(200\),字符集为\([1,100]\)的串。使得其中能够从中间分成左右两个完全一样的子序列的个数恰好为\(n\)。

题解

一个很\(naive\)的想法就是把\(n\)二进制分解,然后对于每一个二的若干次幂找一段连续的构建一下,长成\(123...123...\)这个样子。然而发现这样子的数字以及长度似乎都爆炸了。

换个方式,我们来倍增,假设\(XY\)这个串有\(ans\)对,那么\(aXaY\)就有\(2ans\)对,\(aXYa\)就有\(ans+1\)对。那么就很资磁了,倍增一下就好了。

至于为什么代码里\(n\)要加一,因为如果只按代码的方式做的话你会发现少了一对。

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
#define ll long long
ll n;int cnt;
deque<int> Q1,Q2;
void Work(ll n)
{
if(n==1)return;
Work(n>>1);++cnt;
Q1.push_front(cnt);Q2.push_front(cnt);
if(n&1)++cnt,Q1.push_front(cnt),Q2.push_back(cnt);
}
int main()
{
cin>>n;Work(n+1);
printf("%d\n",(int)(Q1.size()+Q2.size()));
while(!Q1.empty())printf("%d ",Q1.front()),Q1.pop_front();
while(!Q2.empty())printf("%d ",Q2.front()),Q2.pop_front();
puts("");return 0;
}

D - Colorful Balls

翻译

有\(n\)个球排成一行,每一个球都有颜色和重量,如果两个球颜色相同并且重量和小于\(X\)那么他们可以交换位置,如果两个球颜色不同并且重量和小于\(Y\)那么他们可以交换位置。求有多少种不同的颜色序列。

题解

不难发现如果\(u\)可以和\(a,b\)交换,那么\(u,a,b\)就可以任意交换位置。那么如果我们把可以交换位置的球用边给连起来,那么一个联通块中的球可以任意交换位置。因此,一个联通块的贡献就是球的个数的阶乘除掉每种颜色球的个数的阶乘。而最终的答案显然就是所有联通块的乘积。

先考虑同色的连边。显然如果一个球能够和同色的连边,那么它必定可以和同色的重量最小的球连边,而连边方式有两种,第一种是和同色最小值的和小于\(X\),这样子可以直接连边。第二种连边方式则是这个球和异色最小值的和小于\(Y\),那么同色的最小值也必定可以和这个异色最小值连边,也就是这个球可以和同色最小值连边。如果我们把同色球按照重量排序,显然一个前缀之间都可以互换。而不能互换的显然是一段后缀,并且显然它们也不能和任何异色球连边,因为它们不能和异色最小值连边,也必定不能和其他异色的球连边。那么我们处理完所有同色的球之后,显然同色球可以合在一起考虑,只需要考虑重量最小的球对外的连边。那么再按照重量排一遍序,显然可以链接的一定是一段前缀,那么直接考虑这一段前缀的贡献就好了。

我竟然做出来了?这题真简单?

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define MAX 200200
#define MOD 1000000007
using namespace std;
#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,X,Y,ans;
struct Ball{int c,w;}B[MAX];
bool operator<(Ball a,Ball b){if(a.c!=b.c)return a.c<b.c;return a.w<b.w;}
int jc[MAX],jv[MAX],inv[MAX];
int pmn[MAX],smn[MAX],sz[MAX],W[MAX],p[MAX];
bool cmp(int i,int j){return W[i]<W[j];}
int main()
{
n=read();X=read();Y=read();
for(int i=1;i<=n;++i)B[i].c=read(),B[i].w=read();
jc[0]=jv[0]=inv[0]=inv[1]=1;
for(int i=2;i<=n;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=1;i<=n;++i)jc[i]=1ll*jc[i-1]*i%MOD,jv[i]=1ll*jv[i-1]*inv[i]%MOD;
sort(&B[1],&B[n+1]);
memset(pmn,63,sizeof(pmn));
memset(smn,63,sizeof(smn));
memset(W,63,sizeof(W));
for(int i=1,j;i<=n;i=j+1)
{
j=i;while(j<n&&B[i].c==B[j+1].c)++j;
pmn[B[i].c]=smn[B[i].c]=B[i].w;
}
for(int i=1;i<=n;++i)pmn[i]=min(pmn[i],pmn[i-1]);
for(int i=n;i>=1;--i)smn[i]=min(smn[i],smn[i+1]);
for(int i=1,j;i<=n;i=j+1)
{
j=i;while(j<n&&B[i].c==B[j+1].c)++j;
int d=min(pmn[B[i].c-1],smn[B[i].c+1]);
int cnt=1;
for(int k=i+1;k<=j;++k)
if(B[i].w+B[k].w<=X||B[k].w+d<=Y)++cnt;
else break;
sz[B[i].c]=cnt;W[B[i].c]=B[i].w;
}
for(int i=1;i<=n;++i)p[i]=i;
sort(&p[1],&p[n+1],cmp);
for(int i=1;i<=n;++i)
if(i==1||W[p[i]]+W[p[1]]<=Y)
ans+=sz[p[i]];
ans=jc[ans];
for(int i=1;i<=n;++i)
if(i==1||W[p[i]]+W[p[1]]<=Y)
ans=1ll*ans*jv[sz[p[i]]]%MOD;
printf("%d\n",ans);
return 0;
}

E - Camel and Oases

翻译

有\(n\)个绿洲排成一条直线,有一只骆驼,可以带体积为\(V\)的水,在绿洲可以补满水。现在骆驼要访问所有的绿洲,它有两种运动方式,第一种直接走过去,要求两个绿洲直接的距离不能超过\(V\)。另外一种是跳过去,\(V\)变成\([\frac{V}{2}]\),然后直接到达,当\(V=0\)时就不能跳了。

现在对于每一个绿洲作为起点,回答能否遍历所有的绿洲。

题解

发现\(V/2^k\)一共就\(log\)种取值,显然可以预处理出对于每一个起点,\(V=V/2^k\)时能够到达的区间。这样子我们就得到了一条条线段。

那么问题等价于回答,对于每一个\(V/2^k\),从中分别选出一条线段,然后每次钦定\(k=0\)的线段,问能否覆盖整个区间。

然后就状压了!设\(sl[S]\)表示用了\(S\)集合中的这些长度的线段(\(V/2^k\)),能够覆盖\([1,x]\)的最大\(x\)值,同理预处理\(sr[S]\),这样子我们就可以知道左右侧能够拼出来的位置。那么每个询问只需要考虑中间一段加入进来之后能够把整个线段联通即可。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 200200
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;
}
void cmax(int &x,int y){if(x<y)x=y;}
void cmin(int &x,int y){if(x>y)x=y;}
int n,V[25],x[MAX],t;
int L[20][MAX],R[20][MAX],mr[MAX];
int sl[1<<19],sr[1<<19];
int main()
{
n=read();V[0]=read();
for(int i=1;i<=n;++i)x[i]=read();
while(V[t])V[t+1]=V[t]>>1,++t;int S=1<<t;
for(int i=0;i<=t;++i)
{
L[i][1]=1;R[i][n]=n;
for(int j=2;j<=n;++j)
if(x[j]-x[j-1]<=V[i])L[i][j]=L[i][j-1];
else L[i][j]=j;
for(int j=n-1;~j;--j)
if(x[j+1]-x[j]<=V[i])R[i][j]=R[i][j+1];
else R[i][j]=j;
}
for(int i=1;i<S;++i)sl[i]=1,sr[i]=n;
sl[0]=0;sr[0]=n+1;
for(int i=0;i<S;++i)
for(int j=1;j<=t;++j)
if(!(i&(1<<(j-1))))
{
cmax(sl[i|(1<<(j-1))],R[j][sl[i]+1]);
cmin(sr[i|(1<<(j-1))],L[j][sr[i]-1]);
}
memset(mr,63,sizeof(mr));
for(int j=0;j<S;++j)cmin(mr[sl[j]],sr[(S-1)^j]);
for(int i=n;~i;--i)mr[i]=min(mr[i],mr[i+1]);
for(int i=1;i<=n;++i)puts(mr[L[0][i]-1]<=R[0][i]+1?"Possible":"Impossible");
return 0;
}

F - Prefix Median

翻译

给定一个长度为\(2n-1\)的数列\(a_i\),定义数列\(b_i\)为\((a_1,a_2,...,a_{2i-1})\)的中位数。

现在对于\(a\)的任意一种排列,有多少种本质不同的\(b\)。

对于\(10^9+7\)取模。

\(n\le 50\)

题解

一个\(2^{2n-1}\)的想法是状压已经用过了哪些\(a_i\),每次选出两个进行更新就可以了。

考虑每次加入两个数,中位数会怎么变化。讨论一下,要么加入一个比中位数大的和一个比中位数小的,然后中位数不变,要么加入两个比中位数小或者大的,改变成前驱或者后继。

因此,我们得到两个结论:1.\(b_i\)的取值范围一定在排序之后的\(a[i]\)到\(a[2n-i]\)之间。2.不存在\(i,j,i<j\),满足\(b_j<b_i<b_{j+1}\)或者\(b_j>b_i>b_{j+1}\)。

我们唯一知道的状态就是\(b_n\)一定是唯一确定的,那么我们考虑反过来做,设\(f[i][l][r]\)表示当前考虑到\(b_i\),还有\(l\)个数\(\le b_{i+1}\),有\(r\)个数\(\gt b_{i+1}\),并且这些数都可以作为当前\(b_i\)的可能取值的方案数。

那么我们的初值就是\(f[n][1][0]=1\),确定一下两侧范围自然扩大,能否把左右选择的范围变大,增量记为\(pl,pr\)。

每次转移的时候枚举一下选择范围内的哪一个数作为接下来的\(b_i\),更新一下\(l,r\)就好了。

这里有一个问题,就是我们是否能否在前面已经确定\(b_{i+1..n}\)的情况下,可以任意选择\(b_i\),答案是能。 我们这样子思考,如果接下来我们要往左挪动,那么我们删去右侧最小的两个数,那么就可以取到接下来可选数中的最大值;如果接下来我们向右挪动,那么我们删去左侧最大的两个数,这样子就可以取到接下来的最小值;如果我们当前位置不变,左侧删去最右的一行、右侧删去最左的一行就可以取到接下来可能的最大最小值。因此我们接下来可以选择任意在\(l,r\)限制内的\(b\)。

那么我们现在只需要计算一下方案数就行了。

考虑\(l,r\)怎么更新,假设我们向左选择了第\(L\)个数,那么显然这之间的都要删去,否则就无法直接跳到这一行了(注意这个操作是变为前驱,即中间的所有值都在某一步中被删去了),而右侧的范围自然拓展,再加上原本的位置变为合法位置,所以转移是\(f[i+1][l][r]\rightarrow f[i][l-L+pl][r+pr+(L>1)]\)。

如果我们向右选择了第\(R\)个数,那么类似的得到转移\(f[i+1][l][r]\rightarrow f[i][l+pl+1][r+pr-R]\)。

两个转移的微小区别在于状态中\(l\)是小于等于,而\(r\)是大于。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MOD 1000000007
#define MAX 101
void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
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[MAX],f[MAX][MAX][MAX],ans;
int main()
{
n=read();for(int i=1;i<n+n;++i)a[i]=read();
sort(&a[1],&a[n+n]);
f[n][1][0]=1;
for(int i=n-1;i;--i)
{
int pl=(a[i]!=a[i+1]),pr=(a[n+n-i]!=a[n+n-i-1]);
for(int l=0;l<=n+n-1;++l)
for(int r=0;l+r<=n+n-1;++r)
if(f[i+1][l][r])
{
for(int L=1;L<=l+pl;++L)add(f[i][l+pl-L+1][r+pr+(L>1)],f[i+1][l][r]);
for(int R=1;R<=r+pr;++R)add(f[i][l+pl+1][r+pr-R],f[i+1][l][r]);
}
}
for(int i=0;i<n+n;++i)
for(int j=0;j<n+n;++j)
add(ans,f[1][i][j]);
printf("%d\n",ans);
return 0;
}

AtCoder Grand Contest 012的更多相关文章

  1. AtCoder Grand Contest 012 A

    A - AtCoder Group Contest Time limit : 2sec / Memory limit : 256MB Score : 300 points Problem Statem ...

  2. AtCoder Grand Contest 012 A - AtCoder Group Contest(贪心)

    Time limit : 2sec / Memory limit : 256MB Score : 300 points Problem Statement There are 3N participa ...

  3. AtCoder Grand Contest 012 C:Tautonym Puzzle

    题目传送门:https://agc012.contest.atcoder.jp/tasks/agc012_c 题目翻译 如果一个字符串是好的,那么这个字符串的前半部分和后半部分肯定一模一样.比如\(a ...

  4. AtCoder Grand Contest 012 D:Colorful Balls

    题目传送门:https://agc012.contest.atcoder.jp/tasks/agc012_d 题目翻译 给你一排一共\(N\)个球,每个球有一个颜色\(c_i\)和一个重量\(w_i\ ...

  5. AtCoder Grand Contest 012 B - Splatter Painting(dp)

    Time limit : 2sec / Memory limit : 256MB Score : 700 points Problem Statement Squid loves painting v ...

  6. AtCoder Grand Contest 012 B Splatter Painting (反向处理 + 记忆化)

    题目链接  agc012 Problem B 题意  给定一个$n$个点$m$条边的无向图,现在有$q$个操作.对距离$v$不超过$d$的所有点染色,颜色编号为$c$. 求每个点最后的颜色状态. 倒过 ...

  7. AtCoder Grand Contest 012 B

    B - Splatter Painting Time limit : 2sec / Memory limit : 256MB Score : 700 points Problem Statement ...

  8. AtCoder Grand Contest 012 D Colorful Balls

    题意: 有N个球排成一行,第i个球颜色为ci, 权为wi, 如果两个同色球权值和 <= X 则它们可以交换: 如果两个异色球权值和 <= Y 则它们可以交换:不限制交换次数,求能到达的颜色 ...

  9. AtCoder Grand Contest 012 B Splatter Painting(记忆化搜索)

    题意: 给一个包含N个顶点,M条边,无自环和重边的简单无向图,初始每个点颜色都为0,每条边的长度为1,连接着ai,bi两个节点.经过若干个操作, 每次将与某个点vi距离不超过di的所有点染成某种颜色c ...

随机推荐

  1. Dynamics 365-Full Text Index on Stopwords

    之前写了一篇关于Online Relevance Search的博文,然后又看到罗勇大神关于Full Text Index的博文:Dynamics CRM中一个查找字段引发的[血案],于是准备写点关于 ...

  2. Apex 中文件夹相关的单元测试

    Salesforce 中的文件夹 在 Salesforce 中,我们可以建立各种文档.报表.仪表板.电子邮件模板等.它们都被保存在相应的文件夹中. Salesforce 的后端将这些文件夹保存为 Fo ...

  3. iOS----------拨打电话的3种方式

    iOS实现拨打电话的方式:   方法一.requestWithURL,此方法拨打前弹出提示 NSMutableString * string = [[NSMutableString alloc] in ...

  4. Android远程桌面助手(Build 0737)

    Android Remote Displayer and Controller Build 0737, Aug 02, 2017 新增功能: 录制MP4文件,突破了Android原生180S的限制 截 ...

  5. ionic3 Loading组件的用法

    import { LoadingController } from 'ionic-angular'; @Component({ selector: 'page-contact', templateUr ...

  6. asp.net core参数保护之自定义要保护的参数类型

    asp.net core参数保护之自定义要保护的参数类型 Intro 为了实现 asp.net core 下的参数保护,扩展了asp.net core 中 DataProtection,可以自动化的保 ...

  7. (办公)mysql连接不上(java.sql.SQLException: null, message from server: "Host 'LAPTOP-O0GA2P8J' is not allowed to connect to this MySQL server")(转)

    转载自csdn文章:https://blog.csdn.net/Tangerine_bisto/article/details/803461511.对所有主机进行访问授权 GRANT ALL PRIV ...

  8. (办公)TOKEN

    token就是HTTP认证,输入正确的token,在放在Authorization header中发送给服务器,认证成功.,就可以正确的拿到接口数据. 举个例子: 第一步:  客户端发送http re ...

  9. MySQL如何判别InnoDB表是独立表空间还是共享表空间

    InnoDB采用按表空间(tablespace)的方式进行存储数据, 默认配置情况下会有一个初始大小为10MB, 名字为ibdata1的文件, 该文件就是默认的表空间文件(tablespce file ...

  10. MVC文件的上传、删除

    public ActionResult FileUpload()        {            Users users = new Users();            users = ( ...