AtCoder Grand Contest 012

A - AtCoder Group Contest

翻译

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

题解

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

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. using namespace std;
  5. #define ll long long
  6. inline int read()
  7. {
  8. int x=0;bool t=false;char ch=getchar();
  9. while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  10. if(ch=='-')t=true,ch=getchar();
  11. while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  12. return t?-x:x;
  13. }
  14. int n,a[300100];ll ans;
  15. int main()
  16. {
  17. n=read();
  18. for(int i=1;i<=n*3;++i)a[i]=read();
  19. sort(&a[1],&a[n+n+n+1]);
  20. for(int i=n+n+n-1,j=1;j<=n;++j,i-=2)ans+=a[i];
  21. cout<<ans<<endl;
  22. return 0;
  23. }

B - Splatter Painting

翻译

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

题解

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

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<vector>
  8. #include<queue>
  9. using namespace std;
  10. #define MAX 100100
  11. #define ll long long
  12. inline int read()
  13. {
  14. int x=0;bool t=false;char ch=getchar();
  15. while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  16. if(ch=='-')t=true,ch=getchar();
  17. while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  18. return t?-x:x;
  19. }
  20. struct Line{int v,next;}e[MAX<<1];
  21. int h[MAX],cnt=1;
  22. inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
  23. int n,m,col[MAX],dis[MAX];
  24. int Q,U[MAX],D[MAX],C[MAX];
  25. void BFS(int S,int d,int c)
  26. {
  27. if(dis[S]>=d)return;dis[S]=d;
  28. queue<int> Q;Q.push(S);
  29. while(!Q.empty())
  30. {
  31. int u=Q.front();Q.pop();
  32. if(!col[u])col[u]=c;
  33. if(!dis[u])continue;
  34. for(int i=h[u];i;i=e[i].next)
  35. if(dis[e[i].v]<dis[u]-1)
  36. {
  37. dis[e[i].v]=dis[u]-1;
  38. Q.push(e[i].v);
  39. }
  40. }
  41. }
  42. int main()
  43. {
  44. n=read();m=read();
  45. for(int i=1;i<=m;++i)
  46. {
  47. int u=read(),v=read();
  48. Add(u,v);Add(v,u);
  49. }
  50. Q=read();memset(dis,-1,sizeof(dis));
  51. for(int i=1;i<=Q;++i)U[i]=read(),D[i]=read(),C[i]=read();
  52. for(int i=Q;i;--i)
  53. BFS(U[i],D[i],C[i]);
  54. for(int i=1;i<=n;++i)printf("%d\n",col[i]);
  55. return 0;
  56. }

C - Tautonym Puzzle

翻译

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

题解

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

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

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

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<queue>
  4. using namespace std;
  5. #define ll long long
  6. ll n;int cnt;
  7. deque<int> Q1,Q2;
  8. void Work(ll n)
  9. {
  10. if(n==1)return;
  11. Work(n>>1);++cnt;
  12. Q1.push_front(cnt);Q2.push_front(cnt);
  13. if(n&1)++cnt,Q1.push_front(cnt),Q2.push_back(cnt);
  14. }
  15. int main()
  16. {
  17. cin>>n;Work(n+1);
  18. printf("%d\n",(int)(Q1.size()+Q2.size()));
  19. while(!Q1.empty())printf("%d ",Q1.front()),Q1.pop_front();
  20. while(!Q2.empty())printf("%d ",Q2.front()),Q2.pop_front();
  21. puts("");return 0;
  22. }

D - Colorful Balls

翻译

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

题解

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

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

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

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<vector>
  8. #define MAX 200200
  9. #define MOD 1000000007
  10. using namespace std;
  11. #define ll long long
  12. inline int read()
  13. {
  14. int x=0;bool t=false;char ch=getchar();
  15. while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  16. if(ch=='-')t=true,ch=getchar();
  17. while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  18. return t?-x:x;
  19. }
  20. int n,X,Y,ans;
  21. struct Ball{int c,w;}B[MAX];
  22. bool operator<(Ball a,Ball b){if(a.c!=b.c)return a.c<b.c;return a.w<b.w;}
  23. int jc[MAX],jv[MAX],inv[MAX];
  24. int pmn[MAX],smn[MAX],sz[MAX],W[MAX],p[MAX];
  25. bool cmp(int i,int j){return W[i]<W[j];}
  26. int main()
  27. {
  28. n=read();X=read();Y=read();
  29. for(int i=1;i<=n;++i)B[i].c=read(),B[i].w=read();
  30. jc[0]=jv[0]=inv[0]=inv[1]=1;
  31. for(int i=2;i<=n;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
  32. for(int i=1;i<=n;++i)jc[i]=1ll*jc[i-1]*i%MOD,jv[i]=1ll*jv[i-1]*inv[i]%MOD;
  33. sort(&B[1],&B[n+1]);
  34. memset(pmn,63,sizeof(pmn));
  35. memset(smn,63,sizeof(smn));
  36. memset(W,63,sizeof(W));
  37. for(int i=1,j;i<=n;i=j+1)
  38. {
  39. j=i;while(j<n&&B[i].c==B[j+1].c)++j;
  40. pmn[B[i].c]=smn[B[i].c]=B[i].w;
  41. }
  42. for(int i=1;i<=n;++i)pmn[i]=min(pmn[i],pmn[i-1]);
  43. for(int i=n;i>=1;--i)smn[i]=min(smn[i],smn[i+1]);
  44. for(int i=1,j;i<=n;i=j+1)
  45. {
  46. j=i;while(j<n&&B[i].c==B[j+1].c)++j;
  47. int d=min(pmn[B[i].c-1],smn[B[i].c+1]);
  48. int cnt=1;
  49. for(int k=i+1;k<=j;++k)
  50. if(B[i].w+B[k].w<=X||B[k].w+d<=Y)++cnt;
  51. else break;
  52. sz[B[i].c]=cnt;W[B[i].c]=B[i].w;
  53. }
  54. for(int i=1;i<=n;++i)p[i]=i;
  55. sort(&p[1],&p[n+1],cmp);
  56. for(int i=1;i<=n;++i)
  57. if(i==1||W[p[i]]+W[p[1]]<=Y)
  58. ans+=sz[p[i]];
  59. ans=jc[ans];
  60. for(int i=1;i<=n;++i)
  61. if(i==1||W[p[i]]+W[p[1]]<=Y)
  62. ans=1ll*ans*jv[sz[p[i]]]%MOD;
  63. printf("%d\n",ans);
  64. return 0;
  65. }

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]\),这样子我们就可以知道左右侧能够拼出来的位置。那么每个询问只需要考虑中间一段加入进来之后能够把整个线段联通即可。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<vector>
  8. using namespace std;
  9. #define ll long long
  10. #define MAX 200200
  11. inline int read()
  12. {
  13. int x=0;bool t=false;char ch=getchar();
  14. while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  15. if(ch=='-')t=true,ch=getchar();
  16. while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  17. return t?-x:x;
  18. }
  19. void cmax(int &x,int y){if(x<y)x=y;}
  20. void cmin(int &x,int y){if(x>y)x=y;}
  21. int n,V[25],x[MAX],t;
  22. int L[20][MAX],R[20][MAX],mr[MAX];
  23. int sl[1<<19],sr[1<<19];
  24. int main()
  25. {
  26. n=read();V[0]=read();
  27. for(int i=1;i<=n;++i)x[i]=read();
  28. while(V[t])V[t+1]=V[t]>>1,++t;int S=1<<t;
  29. for(int i=0;i<=t;++i)
  30. {
  31. L[i][1]=1;R[i][n]=n;
  32. for(int j=2;j<=n;++j)
  33. if(x[j]-x[j-1]<=V[i])L[i][j]=L[i][j-1];
  34. else L[i][j]=j;
  35. for(int j=n-1;~j;--j)
  36. if(x[j+1]-x[j]<=V[i])R[i][j]=R[i][j+1];
  37. else R[i][j]=j;
  38. }
  39. for(int i=1;i<S;++i)sl[i]=1,sr[i]=n;
  40. sl[0]=0;sr[0]=n+1;
  41. for(int i=0;i<S;++i)
  42. for(int j=1;j<=t;++j)
  43. if(!(i&(1<<(j-1))))
  44. {
  45. cmax(sl[i|(1<<(j-1))],R[j][sl[i]+1]);
  46. cmin(sr[i|(1<<(j-1))],L[j][sr[i]-1]);
  47. }
  48. memset(mr,63,sizeof(mr));
  49. for(int j=0;j<S;++j)cmin(mr[sl[j]],sr[(S-1)^j]);
  50. for(int i=n;~i;--i)mr[i]=min(mr[i],mr[i+1]);
  51. for(int i=1;i<=n;++i)puts(mr[L[0][i]-1]<=R[0][i]+1?"Possible":"Impossible");
  52. return 0;
  53. }

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\)是大于。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. using namespace std;
  5. #define MOD 1000000007
  6. #define MAX 101
  7. void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
  8. inline int read()
  9. {
  10. int x=0;bool t=false;char ch=getchar();
  11. while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  12. if(ch=='-')t=true,ch=getchar();
  13. while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  14. return t?-x:x;
  15. }
  16. int n,a[MAX],f[MAX][MAX][MAX],ans;
  17. int main()
  18. {
  19. n=read();for(int i=1;i<n+n;++i)a[i]=read();
  20. sort(&a[1],&a[n+n]);
  21. f[n][1][0]=1;
  22. for(int i=n-1;i;--i)
  23. {
  24. int pl=(a[i]!=a[i+1]),pr=(a[n+n-i]!=a[n+n-i-1]);
  25. for(int l=0;l<=n+n-1;++l)
  26. for(int r=0;l+r<=n+n-1;++r)
  27. if(f[i+1][l][r])
  28. {
  29. for(int L=1;L<=l+pl;++L)add(f[i][l+pl-L+1][r+pr+(L>1)],f[i+1][l][r]);
  30. for(int R=1;R<=r+pr;++R)add(f[i][l+pl+1][r+pr-R],f[i+1][l][r]);
  31. }
  32. }
  33. for(int i=0;i<n+n;++i)
  34. for(int j=0;j<n+n;++j)
  35. add(ans,f[1][i][j]);
  36. printf("%d\n",ans);
  37. return 0;
  38. }

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. 探究高级的Kotlin Coroutines知识

    要说程序如何从简单走向复杂, 线程的引入必然功不可没, 当我们期望利用线程来提升程序效能的过程中, 处理线程的方式也发生了从原始时代向科技时代发生了一步一步的进化, 正如我们的Elisha大神所著文章 ...

  2. Android入门第一课之Java基础

    通知:由于本周六场地申请没通过,所以本周的培训临时取消. 今天给大家带来的是Android入门的第一课,由于教室申请的不确定性,因此,每次培训的内容都会在博客先提前释放出来.首先Android的APP ...

  3. Android 启动APP时黑屏白屏的解决方案

    在开发中,我们在启动app的时候,屏幕会出现一段时间的白屏或者黑屏,不同设备时间长短不同.很影响用户体验. 首先分析一下,产生这个现象的原因,当我们在启动一个应用时,系统会去检查是否已经存在这样一个进 ...

  4. springboot 学习之路 8 (整合websocket(1))

    目录:[持续更新.....] spring 部分常用注解 spring boot 学习之路1(简单入门) spring boot 学习之路2(注解介绍) spring boot 学习之路3( 集成my ...

  5. web.xml设置过滤直接访问

    <security-constraint> <web-resource-collection> <web-resource-name>JSPs</web-re ...

  6. MS SQL自定义函数IsPositiveInteger

    判断字符串是否为正整数,0开始的的数字不算. SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE FUNCTION [dbo].[svf_I ...

  7. c/c++ 继承与多态 继承中的public, protected, private

    问题:类B私有继承类A,类A有个protected成员,那么在类B的成员函数里是否可以使用类A的protected成员? 可以使用. 估计有的同学说不对吧,类B都私有继承了类A了,怎么还能访问类A的p ...

  8. June. 24th 2018, Week 26th. Sunday

    Beautiful things don't ask for attention. 真正美丽的东西,并不会刻意寻求别人的注目. From The Secret Life of Walter Mitty ...

  9. 怎样保证socket.recv接收完数据

    最近在使用python进行网络编程开发一个通用的tcpclient测试小工具.在使用socket进行网络编程中,如何判定对端发送一条报文是否接收完成,是进行socket网络开发必须要考虑的一个问题.这 ...

  10. Git命令行管理代码、安装及使用

    出处:https://www.cnblogs.com/ximiaomiao/p/7140456.html Git安装和使用     目的:通过Git管理github托管项目代码 一.下载安装Git 1 ...