AtCoder Grand Contest 011

upd:这篇咕了好久,前面几题是三周以前写的。。。

AtCoder Grand Contest 011

A - Airport Bus

翻译

有\(n\)个乘客到达了飞机场,现在他们都要坐车离开机场。第\(i\)个乘客到达的时间是\(T_i\),一个乘客必须在\([T_i,T_i+k]\)时刻做到车,否则他会生气。一辆车最多可以坐\(C\)个人。问最少安排几辆车可以让所有人都不生气。

题解

从前往后贪心即可。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<algorithm>
  4. using namespace std;
  5. #define MAX 100100
  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,C,K,T[MAX],ans,s,t;
  15. int main()
  16. {
  17. n=read();C=read();K=read();
  18. for(int i=1;i<=n;++i)T[i]=read();
  19. sort(&T[1],&T[n+1]);
  20. for(int i=1;i<=n;++i)
  21. if(!s)++ans,s=1,t=T[i];
  22. else
  23. {
  24. if(s==C)++ans,s=1,t=T[i];
  25. else
  26. {
  27. if(T[i]-t>K)++ans,s=1,t=T[i];
  28. else ++s;
  29. }
  30. }
  31. printf("%d\n",ans);
  32. return 0;
  33. }

B - Colorful Creatures

翻译

见洛谷

题解

显然不合法的在排序之后是一段前缀,那么倒推哪些合法即可。

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

C - Squared Graph

翻译

给定一个\(n\)个点\(m\)条边的图,构建一个\(n^2\)个点的图,新图的每个点都可以看成一个二元组,新图上的点\((a,b)\)和\((a',b')\)之间有边,当且仅当原图中\((a,a'),(b,b')\)之间有边,问新图的联通块个数。

题解

不太会,抄了一遍代码,从这里抄的

大概理解一下就是,首先考虑所有二元组很不好考虑,拆分行列,考虑情况。首先把所有没有连上的单点全部拿出来把贡献直接算好,接下来只会考虑所有存在边的联通块。考虑一下如果两个点\((a,b),(x,y)\)在新图中连在一起,那么必定在原图中存在一条\(a\rightarrow x,b\rightarrow y\)的路径,并且满足两条路径的长度相同。

如果一个联通块是一个二分图,那么它自身就会贡献\(2\)的答案,即把二分图黑白染色之后左右分开,显然把两边的点分别放在二元组的前面都会形成一个联通块;否则会贡献\(1\)的答案。然后考虑任选两个不连通的图,他们之间的边的关系都可以在新图之中构成一个新的联通块,所以把贡献加上就好了。

  1. #include<iostream>
  2. #include<cstdio>
  3. using namespace std;
  4. #define ll long long
  5. #define MAX 100100
  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. struct Line{int v,next;}e[MAX<<2];
  15. int h[MAX],cnt=1;
  16. inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
  17. bool fl;int sum;
  18. int dep[MAX];bool vis[MAX];
  19. int n,m;ll ans;
  20. void dfs(int u,int ff)
  21. {
  22. vis[u]=true;++sum;
  23. for(int i=h[u];i;i=e[i].next)
  24. if(vis[e[i].v]&&e[i].v!=ff)fl|=dep[u]==dep[e[i].v];
  25. else if(!vis[e[i].v])dep[e[i].v]=dep[u]^1,dfs(e[i].v,u);
  26. }
  27. int main()
  28. {
  29. n=read();m=read();
  30. for(int i=1;i<=m;++i)
  31. {
  32. int u=read(),v=read();
  33. Add(u,v);Add(v,u);
  34. }
  35. int node=0,t1=0,t2=0;
  36. for(int i=1;i<=n;++i)
  37. {
  38. if(vis[i])continue;
  39. fl=false;sum=0;dfs(i,0);
  40. if(sum==1)ans+=n*2-1,++node;
  41. else if(!fl)ans+=2,++t1;
  42. else ++ans,++t2;
  43. }
  44. ans-=1ll*(node-1)*node;
  45. ans+=1ll*t1*(t1-1)*2+1ll*t2*(t2-1)+1ll*t1*t2*2;
  46. cout<<ans<<endl;
  47. return 0;
  48. }

D - Half Reflector

翻译

有一个神仙机器,你可以从它的左边或者右边丢一个球进去,它有两种状态\(A,B\)。如果处在\(A\)状态,你从哪里丢进来的就会从哪里吐出去,然后立即变成\(B\)状态。如果处在\(B\)状态,你从哪边丢进去就会从另外一边吐出来,然后立即变成\(A\)状态。现在把\(n\)台这样的机器放在一排,告诉你他们处在什么状态。然后从最左边放\(K\)次球,每当前面那个球出去之后就放第二个。问最后的机器的状态是啥。

题解

先想想一个球什么时候会从左边出来,什么时候从右边出来。如果它从左边出来,只可能是第一个机器处于\(A\)状态。我们来感性理解一下。首先加入你到达了中间某个位置\(i\),并且它在这里被弹了回来,因为你到了\(i\),所以\(i-1\)原先一定是\(B\)状态,所以它现在一定是\(A\)状态,那么你又被接着弹回去了,那么你又会回到\(i\),而\(i\)刚刚是\(A\),所以现在是\(B\),所以会走到\(i+1\),然后重复此个过程,它一定会向右走。

考虑一下这个串怎么变化。如果最高位是\(A\),直接变成\(B\)完事。否则的话,我们发现首先把它们全部取反,然后原来\(A\)之前的那个\(B\)没有变反,原来\(B\)前面的那个\(A\)也没有变反。所以这个操作可以看成先把它左移一位(高位截掉),再全部取反,最后一个位置显然是补上一个\(A\)。发现做完最多\(2n\)次之后就和原来的串无关了,就变成了\(ABABAB...\)或者\(BABABA...\)这样子了。那就暴力做个\(2n\)次,剩下的判断一下就好啦,当然这里情况可能有些复杂,仔细手玩一下再写代码。

蛤?怎么模拟?你把数组在后面延长不就好了吗?

  1. #include<iostream>
  2. #include<cstdio>
  3. using namespace std;
  4. #define MAX 200200
  5. int n,K,l,r,p;
  6. char S[MAX];int a[MAX<<2];
  7. int main()
  8. {
  9. scanf("%d%d",&n,&K);scanf("%s",S+1);
  10. l=1,r=n,p=0;
  11. for(int i=1;i<=n;++i)a[i]=S[i]=='A';
  12. for(int i=1;i<=n+n;++i)
  13. {
  14. if(a[l]^p)a[l]^=1;
  15. else ++l,p^=1,a[++r]=p^1;
  16. if(i==K)
  17. {
  18. for(int j=l;j<=r;++j)putchar((a[j]^p^1)+'A');
  19. puts("");return 0;
  20. }
  21. }
  22. if((n&1)&&(K&1))a[l]^=1;
  23. for(int i=l;i<=r;++i)putchar((a[i]^p^1)+'A');
  24. return 0;
  25. }

E - Increasing Numbers

翻译

给定一个数\(n\),\(n\le 10^{500,000}\),问\(n\)最少可以拆分成几个不降数的和。一个不降数是在十进制位下,从高位往低位看,每个数都不会比高位的数更小的数。

题解

找啊找啊找性质。然而我太菜了,找不出性质。

首先意识不降的数一定能够拆分成若干个\(11....11\)的形式,因为数字不降,所以这个个数不会超过\(9\)个。那么按照这个方向考虑,假设最终的答案中我们的所有数字被我们拆成了若干个\(1...1\)的形式,他们分别有\(a_i\)个\(1\)。那么等式算一下就是\(\sum_{i=1}^{9k} (10^{a_{i-1}}-1)=9n\)。转化一下就是\(\sum_{i=1}^{9k} 10^{a_i}=9n+9k\),也就是\(9n+9k\)的所有位置上的数字之后恰好小于等于\({9k}\)。那就直接大力枚举\(k\)就好了。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. using namespace std;
  5. #define MAX 500500
  6. char ch[MAX];
  7. int a[MAX<<1],n,s;
  8. int main()
  9. {
  10. scanf("%s",ch+1);n=strlen(ch+1);
  11. for(int i=n;i;--i)a[i]=(ch[n-i+1]-48)*9;
  12. for(int i=1;i<=n;++i)a[i+1]+=a[i]/10,a[i]%=10;
  13. if(a[n+1])++n;
  14. for(int i=1;i<=n;++i)s+=a[i];
  15. for(int i=1;i<=n*9;++i)
  16. {
  17. a[1]+=9;int p=1;s+=9;
  18. while(a[p]>=10)
  19. {
  20. s-=a[p+1];a[p+1]+=a[p]/10;s+=a[p+1];
  21. s-=a[p];a[p]%=10;s+=a[p];
  22. ++p;if(p>n)n=p;
  23. }
  24. if(s<=i*9){printf("%d\n",i);return 0;}
  25. }
  26. return 0;
  27. }

F - Train Service Planning

翻译

有\(n\)段铁路,\(n+1\)个车站,第\(i\)段铁路连接着站台\(i-1\)和站台\(i\)。第\(i\)段铁路行驶时间为\(A_i\),铁路有两种,有一条路或者两条路,即一次可以开过一辆火车或者两辆火车。现在从\(0\)到\(n\)和从\(n\)到\(0\)每经过\(K\)个单位时间就会发出一辆车,一辆车可以在一个站台停任意久的时间,显然不能被后面的同向的车给追上,现在需要安排一个车的行驶方式,使得两侧运行的车的总运行时间最小。

题解

首先每隔\(K\)个单位时间就会发出一辆新车,意味着所有的运算可以等效的理解为在模\(K\)意义下进行。我们假设我们知道两辆车在每一个位置停下的时间,从\(0\rightarrow n\)的设为\(t1[i]\),反过来的设为\(t2[i]\),那么我们就可以得到一辆车通过一段路的时间的区间。设\(S\)为前缀和。从\(0\rightarrow n\)的车的通过第\(i\)段路的时间是\([S(A,i-1)+S(t1,i-1),S(A,i)+S(t1,i-1)]\),反过来运行的车的通过时间同理,我们可以用后缀和表示出来,然后后缀又可以改写成总和减去一段前缀,也就是\([Sum-S(A,i)-S(t2,i-1),Sum-S(A,i-1)-S(t2,i-1)]\)。而总和的话,我们可以强制认为后面从后往前的车在\(0\)车站还要多停一会儿,也就是强制让\(sum\)是\(K\)的倍数,那么在模\(K\)的意义下就可以直接把\(Sum\)省略掉。

对于双向轨道而言,我们并没有任何限制,对于单向轨道而言,显然强制两车通过同一段路的时间不能交。那么可以得到一系列的不等式。最终得到的也就是形如\(S(t1,i)+S(t2,i)\notin [-2S(A,i),-2S(A,i-1)]\)。当然,这些东西全部都在模意义下看。也因为在模意义下,所以不属于可以取补化为属于,即\(S(t1,i)+S(t2,i)\)要在某个特定区间内。而题目要求的东西就是要最小化\(S(t1,n)+S(t2,n)\)。而问题也同时变为,给定\(n\)个区间,每次都要向前走若干距离,并且第\(i\)步走完后位置必须在模意义下的给定区间中,求最小的移动距离。

因为可以在起始车站停留,所以我们可以任意选择起始位置,贪心的考虑,显然每次走到目标区间的左端点一定是最优的。那么我们只需要预处理从每一个位置出发一直走左端点的最小距离即可。设\(f[i]\)表示当前从第\(i\)个限制的左端点出发的距离。考虑倒推,每次更新完一个区间之后就可以用线段树更新取值,这样子就很容易知道下一个位置要从哪里转移。接下来只需要枚举起点即可计算答案。

  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. #define lson (now<<1)
  12. #define rson (now<<1|1)
  13. void WA(){puts("-1");exit(0);}
  14. inline int read()
  15. {
  16. int x=0;bool t=false;char ch=getchar();
  17. while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
  18. if(ch=='-')t=true,ch=getchar();
  19. while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  20. return t?-x:x;
  21. }
  22. int n,K,top;
  23. ll a[MAX],b[MAX],t[MAX<<2];
  24. ll L[MAX],R[MAX],f[MAX],s[MAX],S[MAX];
  25. void pushdown(int now)
  26. {
  27. if(!t[now])return;
  28. t[lson]=t[rson]=t[now];
  29. t[now]=0;
  30. }
  31. void modify(int now,int l,int r,int L,int R,int w)
  32. {
  33. if(L>R)return;
  34. if(L<=l&&r<=R){t[now]=w;return;}
  35. int mid=(l+r)>>1;pushdown(now);
  36. if(L<=mid)modify(lson,l,mid,L,R,w);
  37. if(R>mid)modify(rson,mid+1,r,L,R,w);
  38. }
  39. int Query(int now,int l,int r,int p)
  40. {
  41. if(l==r)return t[now];
  42. int mid=(l+r)>>1;pushdown(now);
  43. if(p<=mid)return Query(lson,l,mid,p);
  44. else return Query(rson,mid+1,r,p);
  45. }
  46. ll Query(int x)
  47. {
  48. int d=Query(1,1,top,x);
  49. if(!d)return 0;
  50. return f[d]+(S[L[d]]%K-S[x]%K+K)%K;
  51. }
  52. int main()
  53. {
  54. n=read();K=read();
  55. for(int i=1;i<=n;++i)
  56. {
  57. a[i]=read(),b[i]=read();
  58. s[i]=s[i-1]+a[i];
  59. if(b[i]==1&&a[i]+a[i]>K)WA();
  60. }
  61. for(int i=n;i;--i)
  62. if(b[i]==1)L[i]=(-2*s[i-1]%K+K)%K,R[i]=(-2*s[i]%K+K)%K;
  63. else L[i]=0,R[i]=K-1;//No limit
  64. for(int i=1;i<=n;++i)S[++top]=L[i],S[++top]=R[i];
  65. sort(&S[1],&S[top+1]);top=unique(&S[1],&S[top+1])-S-1;
  66. for(int i=n;i;--i)
  67. {
  68. L[i]=lower_bound(&S[1],&S[top+1],L[i])-S;
  69. R[i]=lower_bound(&S[1],&S[top+1],R[i])-S;
  70. f[i]=Query(L[i]);
  71. if(L[i]>R[i])modify(1,1,top,R[i]+1,L[i]-1,i);
  72. else modify(1,1,top,1,L[i]-1,i),modify(1,1,top,R[i]+1,top,i);
  73. }
  74. ll ans=1e18;
  75. for(int i=top;i;--i)ans=min(ans,Query(i));
  76. cout<<ans+s[n]+s[n]<<endl;
  77. return 0;
  78. }

AtCoder Grand Contest 011的更多相关文章

  1. AtCoder Grand Contest 011 F - Train Service Planning

    题目传送门:https://agc011.contest.atcoder.jp/tasks/agc011_f 题目大意: 现有一条铁路,铁路分为\(1\sim n\)个区间和\(0\sim n\)个站 ...

  2. 【Atcoder Grand Contest 011 F】Train Service Planning

    题意:给\(n+1\)个站\(0,\dots,n\),连续的两站\(i-1\)和\(i\)之间有一个距离\(A_i\),其是单行(\(B_i=1\))或双行(\(B_i=2\)),单行线不能同时有两辆 ...

  3. AtCoder Grand Contest 011 E - Increasing Numbers(灵性乱搞)

    题意: 当一个整数高位数字总不小于低位数字,或者说写成字符串之后单调不下降,称之为上升数.求一个整数最少能表示为多少个上升数的和.(n<=1e500000) 分析: 考虑那些不下降的数字,一定可 ...

  4. AtCoder Grand Contest 011题解

    传送门 \(A\) 直接按时间排序之后贪心就可以了 const int N=1e5+5; int a[N],q[N],c,k,h,t,n,res; inline int min(R int x,R i ...

  5. AtCoder Grand Contest 012

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

  6. AtCoder Grand Contest 031 简要题解

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

  7. AtCoder Grand Contest 010

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

  8. AtCoder Grand Contest 009

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

  9. AtCoder Grand Contest 008

    AtCoder Grand Contest 008 A - Simple Calculator 翻译 有一个计算器,上面有一个显示按钮和两个其他的按钮.初始时,计算器上显示的数字是\(x\),现在想把 ...

随机推荐

  1. NOIP2018 模拟赛(二十二)雅礼NOI

    Preface 这次的题目都是NOI+的题,所以大家的分数都有点惨烈. 依靠T1大力骗分水到Rank2 所以想看正解的话看这里吧 A. 「雅礼NOI2018模拟赛(一) Day1」树 看一眼题目感觉十 ...

  2. [Spark][Python]Wordcount 例子

    [training@localhost ~]$ hdfs dfs -cat cats.txt The cat on the matThe aardvark sat on the sofa[traini ...

  3. Docker容器学习梳理 - 基础环境安装

    以下是centos系统安装docker的操作记录 1)第一种方法:采用系统自带的docker安装,但是这一般都不是最新版的docker安装epel源[root@docker-server ~]# wg ...

  4. centos下部署NTP时间服务器同步环境记录

    1)服务端部署 安装所需软件包 [root@test ~]# yum -y install ntp ntpdate 服务端自己先手工同步一次时间. [root@test ~]# ntpdate ntp ...

  5. Python-复习-文件操作-21

    # 文件处理 # 打开文件 #open('路径','打开方式','指定编码方式') # 打开方式 r w a r+ w+ a+ b #r+ 打开文件直接写 和读完再写 # 编码方式 —— utf-8 ...

  6. 补充照片:某基同学使用Bing词典

    某基同学使用Bing词典的照片

  7. IO学习

    ---恢复内容开始--- 命名规则: 1.类名使用 UpperCamelCase 风格,必须遵从驼峰形式,但以下情形例外:(领域模型 的相关命名)DO / BO / DTO / VO 等. 2.方法名 ...

  8. 转帖--计算机网络基础知识大总汇 https://www.jianshu.com/p/674fb7ec1e2c?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

    计算机网络基础知识大总汇 龙猫小爷 关注 2016.09.14 23:01* 字数 12761 阅读 30639评论 35喜欢 720 一.什么是TCP/IP 网络和协议 1.     TCP/IP是 ...

  9. MyBatis是如何解决Sql注入的

    转:[转]mybatis如何防止sql注入 java中预处理PrepareStatement为什么能起到防止SQL注入的作用??!! 一.SQL注入 sql注入大家都不陌生,是一种常见的攻击方式,攻击 ...

  10. 属性动画总结(Property Animation)

    一.概述 属性动画可以作用在View的属性上,对属性进行修改,而且不要求对应的属性一定是有显示效果的. 二.属性动画的实现方式 1.基础的类Animator Animator是一个抽象类,是属性动画的 ...