AtCoder Grand Contest 011

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

AtCoder Grand Contest 011

A - Airport Bus

翻译

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

题解

从前往后贪心即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAX 100100
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,C,K,T[MAX],ans,s,t;
int main()
{
n=read();C=read();K=read();
for(int i=1;i<=n;++i)T[i]=read();
sort(&T[1],&T[n+1]);
for(int i=1;i<=n;++i)
if(!s)++ans,s=1,t=T[i];
else
{
if(s==C)++ans,s=1,t=T[i];
else
{
if(T[i]-t>K)++ans,s=1,t=T[i];
else ++s;
}
}
printf("%d\n",ans);
return 0;
}

B - Colorful Creatures

翻译

见洛谷

题解

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

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
#define MAX 100100
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;ll a[MAX],s;
int main()
{
n=read();
for(int i=1;i<=n;++i)a[i]=read();
sort(&a[1],&a[n+1]);
for(int i=1;i<=n;++i)a[i]+=a[i-1];
for(int i=n-1;i;--i)
if(a[i]*2>=a[i+1]-a[i])++ans;
else break;
printf("%d\n",ans);
return 0;
}

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\)的答案。然后考虑任选两个不连通的图,他们之间的边的关系都可以在新图之中构成一个新的联通块,所以把贡献加上就好了。

#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
#define MAX 100100
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<<2];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
bool fl;int sum;
int dep[MAX];bool vis[MAX];
int n,m;ll ans;
void dfs(int u,int ff)
{
vis[u]=true;++sum;
for(int i=h[u];i;i=e[i].next)
if(vis[e[i].v]&&e[i].v!=ff)fl|=dep[u]==dep[e[i].v];
else if(!vis[e[i].v])dep[e[i].v]=dep[u]^1,dfs(e[i].v,u);
}
int main()
{
n=read();m=read();
for(int i=1;i<=m;++i)
{
int u=read(),v=read();
Add(u,v);Add(v,u);
}
int node=0,t1=0,t2=0;
for(int i=1;i<=n;++i)
{
if(vis[i])continue;
fl=false;sum=0;dfs(i,0);
if(sum==1)ans+=n*2-1,++node;
else if(!fl)ans+=2,++t1;
else ++ans,++t2;
}
ans-=1ll*(node-1)*node;
ans+=1ll*t1*(t1-1)*2+1ll*t2*(t2-1)+1ll*t1*t2*2;
cout<<ans<<endl;
return 0;
}

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\)次,剩下的判断一下就好啦,当然这里情况可能有些复杂,仔细手玩一下再写代码。

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

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 200200
int n,K,l,r,p;
char S[MAX];int a[MAX<<2];
int main()
{
scanf("%d%d",&n,&K);scanf("%s",S+1);
l=1,r=n,p=0;
for(int i=1;i<=n;++i)a[i]=S[i]=='A';
for(int i=1;i<=n+n;++i)
{
if(a[l]^p)a[l]^=1;
else ++l,p^=1,a[++r]=p^1;
if(i==K)
{
for(int j=l;j<=r;++j)putchar((a[j]^p^1)+'A');
puts("");return 0;
}
}
if((n&1)&&(K&1))a[l]^=1;
for(int i=l;i<=r;++i)putchar((a[i]^p^1)+'A');
return 0; }

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\)就好了。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAX 500500
char ch[MAX];
int a[MAX<<1],n,s;
int main()
{
scanf("%s",ch+1);n=strlen(ch+1);
for(int i=n;i;--i)a[i]=(ch[n-i+1]-48)*9;
for(int i=1;i<=n;++i)a[i+1]+=a[i]/10,a[i]%=10;
if(a[n+1])++n;
for(int i=1;i<=n;++i)s+=a[i];
for(int i=1;i<=n*9;++i)
{
a[1]+=9;int p=1;s+=9;
while(a[p]>=10)
{
s-=a[p+1];a[p+1]+=a[p]/10;s+=a[p+1];
s-=a[p];a[p]%=10;s+=a[p];
++p;if(p>n)n=p;
}
if(s<=i*9){printf("%d\n",i);return 0;}
}
return 0;
}

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\)个限制的左端点出发的距离。考虑倒推,每次更新完一个区间之后就可以用线段树更新取值,这样子就很容易知道下一个位置要从哪里转移。接下来只需要枚举起点即可计算答案。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 200200
#define lson (now<<1)
#define rson (now<<1|1)
void WA(){puts("-1");exit(0);}
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,K,top;
ll a[MAX],b[MAX],t[MAX<<2];
ll L[MAX],R[MAX],f[MAX],s[MAX],S[MAX];
void pushdown(int now)
{
if(!t[now])return;
t[lson]=t[rson]=t[now];
t[now]=0;
}
void modify(int now,int l,int r,int L,int R,int w)
{
if(L>R)return;
if(L<=l&&r<=R){t[now]=w;return;}
int mid=(l+r)>>1;pushdown(now);
if(L<=mid)modify(lson,l,mid,L,R,w);
if(R>mid)modify(rson,mid+1,r,L,R,w);
}
int Query(int now,int l,int r,int p)
{
if(l==r)return t[now];
int mid=(l+r)>>1;pushdown(now);
if(p<=mid)return Query(lson,l,mid,p);
else return Query(rson,mid+1,r,p);
}
ll Query(int x)
{
int d=Query(1,1,top,x);
if(!d)return 0;
return f[d]+(S[L[d]]%K-S[x]%K+K)%K;
}
int main()
{
n=read();K=read();
for(int i=1;i<=n;++i)
{
a[i]=read(),b[i]=read();
s[i]=s[i-1]+a[i];
if(b[i]==1&&a[i]+a[i]>K)WA();
}
for(int i=n;i;--i)
if(b[i]==1)L[i]=(-2*s[i-1]%K+K)%K,R[i]=(-2*s[i]%K+K)%K;
else L[i]=0,R[i]=K-1;//No limit
for(int i=1;i<=n;++i)S[++top]=L[i],S[++top]=R[i];
sort(&S[1],&S[top+1]);top=unique(&S[1],&S[top+1])-S-1;
for(int i=n;i;--i)
{
L[i]=lower_bound(&S[1],&S[top+1],L[i])-S;
R[i]=lower_bound(&S[1],&S[top+1],R[i])-S;
f[i]=Query(L[i]);
if(L[i]>R[i])modify(1,1,top,R[i]+1,L[i]-1,i);
else modify(1,1,top,1,L[i]-1,i),modify(1,1,top,R[i]+1,top,i);
}
ll ans=1e18;
for(int i=top;i;--i)ans=min(ans,Query(i));
cout<<ans+s[n]+s[n]<<endl;
return 0;
}

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. java json字符串传递给 js 时 特殊字符转义错误 研究

    一些换行 回车等符号需要转义 主要注意 单引号 与双引号. 一 如果js以 双引号接收字符串 则转单引号 "  至 \" 否则js报错 二 如果js以 单引号接收字符串 则转单引号 ...

  2. 【转】浅谈JavaScript中forEach与each

    forEach是ES5中操作数组的一种方法,主要功能是遍历数组,例如: var arr = [1,2,3,4]; arr.forEach(alert); 等价于: var arr = [1, 2, 3 ...

  3. echarts 响应式布局

    <body> <!-- 为ECharts准备一个具备大小(宽高)的Dom --> <div id="main" style="width: ...

  4. BZOJ 4804: 欧拉心算

    数论题不多BB,直接开始推导吧: \(\sum_{i=1}^n \sum_{j=1}^n \phi(gcd(i,j))\) \(=\sum_{i=1}^n \sum_{j=1}^n \sum_{d=1 ...

  5. xml解析 使用dom4j操作xml

     使用dom4j操作xml 1 导入 dom4j,的jar包   2 指定要解析的XML文件 SAXReader sr=new SAXReader(); Document document= sr.r ...

  6. 异步编程(async&await)

    前言 本来这篇文章上个月就该发布了,但是因为忙 QuarkDoc 一直没有时间整理,所以耽搁到今天,现在回归正轨. C# 5.0 虽然只引入了2个新关键词:async和await.然而它大大简化了异步 ...

  7. 毕业设计 之 五 PHP语法学习笔记

    毕业设计 之 四 PHP语法学习笔记 作者:20135216 平台:windows10 软件:XAMPP,DreamWeaver 说明:该笔记是对网站编程语言的详细学习 一.PHP基础 0. 关于环境 ...

  8. Java源码--Array

    1. Arrays.asList() 该方法是将数组转化为List,需要注意以下几点: (1)该方法不适用于基本数据类型(byte,short,int,long,float,double,boolea ...

  9. The Last Reader Response——13-17

    Hi, everybody, nice to meet you, this is probably my best and meet you at a time, in the past a seme ...

  10. 使用a标签实现文件的下载与保存

    <a>标签的常规使用是定义超链接,用于从一个页面链接到另一个页面,并且需要指定链接目标href,除了定义超链接外,<a>还可以实现文件的保存,直接设置a标签的href属性,但是 ...