AtCoder Grand Contest 007
AtCoder Grand Contest 007
A - Shik and Stone
翻译
题解
傻逼玩意
#include<cstdio>
int n,m,tot;char ch[10];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
{
scanf("%s",ch+1);
for(int j=1;j<=m;++j)
tot+=ch[j]=='#';
}
puts(tot==n+m-1?"Possible":"Impossible");
return 0;
}
B - Construct Sequences
翻译
题解
诶,简单构造题我也不会做,真的是对于构造一窍不通。
我们让\(a\),\(b\)是两个等差数列,保证\(a_i+b_i\)相等,然后公差比\(n\)大就好,每次读进来一个\(p_i\),你就让对应的\(a\)减去一个\(n-i\)就好了。
#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 20200
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],b[MAX];
int main()
{
n=read();
for(int i=1;i<=n;++i)a[i]=i*(n+1),b[i]=(n-i+1)*(n+1);
for(int i=1;i<=n;++i)a[read()]-=(n-i+1);
for(int i=1;i<=n;++i)printf("%d ",a[i]);puts("");
for(int i=1;i<=n;++i)printf("%d ",b[i]);puts("");
}
C - Pushing Balls
翻译
数轴上有\(n\)个球和\(n+1\)个洞,每个球都在两个洞的中间,假设把所有东西放在一起,假设相邻两个物品的距离为\(d_i\),那么\(d_i-d_{i-1}=x\)。每次会等概率选择一个球,并且等概率选择它向左还是向右,它会一直朝着那个方向走,直到掉进坑里,如果这个洞里已经有球,它会从这个洞上面直接过去,继续移动。求所有合法方案中球移动的距离和的期望。一个合法方案是所有球都恰好进入了一个洞,并且只有一个洞没有球。
题解
神仙题,不会。DZYO的题解
官方题解:
在移动完一个球之后,重编号所有的洞和球,每个球仍然在两个洞之间。再重新计算期望意义下相邻的球和洞之间的距离,发现期望距离仍然是一个等差数列,然后从一号球开始顺次计算答案。
代码是照着打的。
#include<iostream>
#include<cstdio>
using namespace std;
double d,x,n,ans;
int main()
{
cin>>n>>d>>x;
for(int i=n;i;--i)
{
double sum=(d*2*n+n*(n+n-1)*x);
ans+=sum/2/n;
double dd=(d*(n+n-2)+d+2*x+3*d+3*x)/2/n;
sum-=(4*d+4*n*x-2*x)/2/n;--n;
d=dd;x=(sum-2*n*d)/n/(n+n-1);
}
printf("%.10lf\n",ans);
return 0;
}
D - Shik and Game
翻译
(什么傻吊题面)
有一个数轴,初始情况下玩家在\(0\)位置,出口在\(E\)位置,数轴上还有\(n\)只熊,你只要到了它的位置,再过\(T\)个单位时间它所在的位置就会出现一个金币。求从出发到捡完所有金币再到出口的最短时间。
题解
显然是把熊按照维护分成若干段,先访问过这一段的所有熊,再回到第一个熊,再顺次拿走所有金币。考虑一个暴力\(dp\),设\(f[i]\)表示当前到了\(i\)并且前面的金币都拿完的最短时间,然后得到式子\(f[i]=min(f[j]+max(t,2*(x[i]-x[j+1])))\),转移很显然。
发现走一段回去再走过来访问到每只熊的时间恰好是这段路程的两倍。意味着维护一下当且可以转移过来的位置,使得距离大于\(t\),那么它一定是一段前缀,那么记一下前缀最小值就完事了。
#include<iostream>
#include<cstdio>
#include<cstring>
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;
}
int n,E,T,x[MAX];
ll ans,f[MAX],mn=1e18;
int main()
{
n=read();E=read();T=read();
for(int i=1;i<=n;++i)x[i]=read();
memset(f,63,sizeof(f));f[0]=0;
for(int i=1,j=0;i<=n;++i)
{
for(;T<=(x[i]-x[j+1])<<1;++j)mn=min(mn,f[j]-2*x[j+1]);
if(j<i)f[i]=min(f[i],f[j]+T);
f[i]=min(f[i],mn+2*x[i]);
}
cout<<f[n]+E<<endl;
return 0;
}
E - Shik and Travel
翻译
给定一棵二叉树,每个节点的儿子数要么是\(2\)要么是\(0\)(除叶子节点外的所有点的度数都是\(2\))。现在你要访问所有叶子节点。要求从根节点出发,最后再回到根。每天你可以选择一个没有去过的叶子节点,然后走过去,花费就是路径上的权值之和。每条边都必须恰好被走过两次,总花费就是除了第一天从根节点出发以及最后一天回到根节点之外的每一天的花费的最大值。最小化这个最大值。
题解
最小化最大值,显然二分。现在考虑如何判定二分值是否合法。
因为每条边必须经过恰好两次,所以一旦进入了一棵子树,必定要走完所有其中所有叶子才能出去。
定义二元组\((a,b)\)表示进入到\(u\)的子树中的时候在子树内产生的花费是\(a\),离开子树那天,在子树内产生的贡献是\(b\)。合并答案的时候枚举两个儿子的所有二元组,不妨设左子树\(i\)是\((a,b)\),右子树\(j\)是\((c,d)\),首先会合并出一条新路径\(b+c+V_i+V_j\),判定是否合法(与二分值比较),如果合法的话,意味着我们可以合并一条路径\((a+V_i,d+V_j)\),调换左右儿子的顺序可以类似得到一个二元组\((c+V_j,b+V_i)\)。发现这样子每次向上维护这个集合内的元素即可维护出答案。然而这样子的状态增长太快,我们需要减少状态。比如说我们匹配出来的结果是\((a+V_i,d+V_j)\),那么我们并不在意\(b,c\)是什么,只需要他们合法就行了。那么对于每一个\(a\),我们能够匹配的\(d\)一定是越小越好。反过来相同。我们设节点\(u\)的二元组集合为\(S_u\),发现\(|S_u|\le 2*min(|S_i|,|S_j|)\)。我们可以选择元素个数较小的那一边,用它的第一维匹配元素较多的那一边的第二维。这样子总的状态数就被压成了\(O(nlgon)\)级别的,再加上二分的答案复杂度就是\(O(nlog(n)log(ans))\)。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define MAX 132000
#define ll long long
#define pi pair<ll,ll>
#define pb push_back
#define mp make_pair
#define fr first
#define sd second
#define vp vector<pi>
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,w;}e[MAX];
int h[MAX],cnt=1;
inline void Add(int u,int v,int w){e[cnt]=(Line){v,h[u],w};h[u]=cnt++;}
int n;ll mid,mn[MAX];
vp f[MAX];
bool cmpx(pi a,pi b){return a.fr<b.fr;}
bool cmpy(pi a,pi b){return a.sd<b.sd;}
void Merge(vp &u,vp ls,vp rs)
{
if(ls.size()>rs.size())swap(ls,rs);
int t1=ls.size(),t2=rs.size();
if(!t1||!t2)return;
sort(ls.begin(),ls.end(),cmpy);
sort(rs.begin(),rs.end(),cmpx);
mn[0]=rs[0].sd;for(int i=1;i<t2;++i)mn[i]=min(mn[i-1],rs[i].sd);
for(int i=0,j=t2-1;i<t1;++i)
{
while(j>=0&&ls[i].sd+rs[j].fr>mid)--j;
if(j>=0)u.pb(mp(ls[i].fr,mn[j]));
}
sort(ls.begin(),ls.end(),cmpx);
sort(rs.begin(),rs.end(),cmpy);
mn[0]=rs[0].fr;for(int i=1;i<t2;++i)mn[i]=min(mn[i-1],rs[i].fr);
for(int i=0,j=t2-1;i<t1;++i)
{
while(j>=0&&ls[i].fr+rs[j].sd>mid)--j;
if(j>=0)u.pb(mp(mn[j],ls[i].sd));
}
}
void dfs(int u)
{
f[u].clear();if(!h[u]){f[u].pb(mp(0,0));return;}
for(int i=h[u];i;i=e[i].next)dfs(e[i].v);
for(int i=h[u];i;i=e[i].next)
for(int j=0,l=f[e[i].v].size();j<l;++j)
f[e[i].v][j].fr+=e[i].w,f[e[i].v][j].sd+=e[i].w;
if(h[u])Merge(f[u],f[e[h[u]].v],f[e[e[h[u]].next].v]);
}
int main()
{
n=read();
for(int i=2,a,v;i<=n;++i)a=read(),v=read(),Add(a,i,v);
ll l=0,r=1e9,ret=1e9;
while(l<=r)
{
mid=(l+r)>>1;dfs(1);
if(f[1].empty())l=mid+1;
else ret=mid,r=mid-1;
}
cout<<ret<<endl;
return 0;
}
F - Shik and Copying String
翻译
题解
大概是,你画个图,发现只需要这样子折一下就好了。那么答案就是最多的折的次数。说不清啊。看一下官方题解的图就好了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define MAX 1000010
int n,ans;
char s[MAX],t[MAX];
queue<int> Q;
int main()
{
scanf("%d",&n);scanf("%s",s+1);scanf("%s",t+1);
if(!strcmp(s+1,t+1)){puts("0");return 0;}
for(int i=n,p=n;i;--i)
{
if(t[i]==t[i-1])continue;
p=min(p,i);while(p&&s[p]!=t[i])--p;
if(!p){puts("-1");return 0;}
while(!Q.empty())
if((int)Q.front()-(int)Q.size()>=i)Q.pop();
else break;
Q.push(p);if(i^p)ans=max(ans,(int)Q.size());
}
printf("%d\n",ans+1);return 0;
}
AtCoder Grand Contest 007的更多相关文章
- AtCoder Grand Contest 007 E:Shik and Travel
题目传送门:https://agc007.contest.atcoder.jp/tasks/agc007_e 题目翻译 现在有一个二叉树,除了叶子每个结点都有两个儿子.这个二叉树一共有\(m\)个叶子 ...
- AtCoder Grand Contest 007题解
传送门 \(A\) 咕咕咕 //quming #include<bits/stdc++.h> #define R register #define fp(i,a,b) for(R int ...
- AtCoder Grand Contest 012
AtCoder Grand Contest 012 A - AtCoder Group Contest 翻译 有\(3n\)个人,每一个人有一个强大值(看我的假翻译),每三个人可以分成一组,一组的强大 ...
- AtCoder Grand Contest 011
AtCoder Grand Contest 011 upd:这篇咕了好久,前面几题是三周以前写的... AtCoder Grand Contest 011 A - Airport Bus 翻译 有\( ...
- AtCoder Grand Contest 031 简要题解
AtCoder Grand Contest 031 Atcoder A - Colorful Subsequence description 求\(s\)中本质不同子序列的个数模\(10^9+7\). ...
- AtCoder Grand Contest 010
AtCoder Grand Contest 010 A - Addition 翻译 黑板上写了\(n\)个正整数,每次会擦去两个奇偶性相同的数,然后把他们的和写会到黑板上,问最终能否只剩下一个数. 题 ...
- AtCoder Grand Contest 009
AtCoder Grand Contest 009 A - Multiple Array 翻译 见洛谷 题解 从后往前考虑. #include<iostream> #include< ...
- AtCoder Grand Contest 008
AtCoder Grand Contest 008 A - Simple Calculator 翻译 有一个计算器,上面有一个显示按钮和两个其他的按钮.初始时,计算器上显示的数字是\(x\),现在想把 ...
- AtCoder Grand Contest 006
AtCoder Grand Contest 006 吐槽 这套题要改个名字,叫神仙结论题大赛 A - Prefix and Suffix 翻译 给定两个串,求满足前缀是\(S\),后缀是\(T\),并 ...
随机推荐
- stop-hbase.sh一直处于等待状态
今天关闭HBase时,输入stop-hbase.sh一直处于等待状态 解决方法: 先输入:hbase-daemon.sh stop master 再输入:stop-hbase.sh就可以关闭HBase ...
- git reset之后找回本地未提交的代码
头脑发热使用了git reset命令回退到了之前的一个版本,结果把本地没有提交的代码给覆盖掉了..... 作为一个bug员自然是想恢复,毕竟重新写还得再测一遍,本着能懒一点是一点的原则,开始了恢复代码 ...
- 20155304《网络对抗》Exp2 后门原理与实践
20155332<网络对抗>Exp2 后门原理与实践 实验内容 (3.5分) (1)使用netcat获取主机操作Shell,cron启动 (0.5分) (2)使用socat获取主机操作Sh ...
- REST-framework快速构建API--频率
前面已经了解了API的认证和授权.认证,是对资源访问者的第一道门,必须有钥匙,你才能进来拿我的资源:授权,是对资源访问者的第二道门,虽然你进来了,但是你可以拿走什么资源,还是我说了算,就是授权. 当然 ...
- React半科普文
React半科普文 什么是React getting started 文件分离 Server端编译 定义一个组件 使用property 组件嵌套 组件更新 Virtual DOM react nati ...
- 前端项目模块化的实践1:搭建 NPM 私有仓库管理源码及依赖
以下是关于前端项目模块化的实践,包含以下内容: 搭建 NPM 私有仓库管理源码及依赖: 使用 Webpack 打包基础设施代码: 使用 TypeScript 编写可靠类库 使用 TypeScript ...
- OpenCV学习资源库
整理了我所了解的有关OpenCV的学习笔记.原理分析.使用例程等相关的博文.排序不分先后,随机整理的.如果有好的资源,也欢迎介绍和分享. 1:OpenCV学习笔记 作者:CSDN数量:55篇博文网址: ...
- Dictionary 对象
Dictionary 对象 对象的存储数据键/项对. 语法 Scripting.Dictionary 说明 Dictionary对象相当于 PERL 关联数组. 项目,可以是任何形式的数据,存储在数组 ...
- 统计学习方法c++实现之六 支持向量机(SVM)及SMO算法
前言 支持向量机(SVM)是一种很重要的机器学习分类算法,本身是一种线性分类算法,但是由于加入了核技巧,使得SVM也可以进行非线性数据的分类:SVM本来是一种二分类分类器,但是可以扩展到多分类,本篇不 ...
- Android 公共库的建立方法
本文主要介绍在android工程中如何将共用代码建成公共包方便其他工程引用.引用后的工程结构分析.library引入方式的优缺点. 自己也写了一些android公共的库,有兴趣的可以参考 Trinea ...