AtCoder Grand Contest 009
AtCoder Grand Contest 009
A - Multiple Array
翻译
题解
从后往前考虑。
#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;
}
int n,a[MAX],b[MAX];
ll ans=0;
int main()
{
n=read();
for(int i=1;i<=n;++i)a[i]=read(),b[i]=read();
for(int i=n;i>=1;--i)
{
a[i]=(b[i]-(a[i]+ans)%b[i])%b[i];
ans+=a[i];
}
cout<<ans<<endl;
return 0;
}
B - Tournament
翻译
有\(n\)个人参加一个锦标赛,因为是淘汰赛制,所以一共会进行\(n-1\)场。现在已知\(1\)号选手是最终的获胜者,并且知道除了\(1\)号之外的每一个人是被谁给淘汰的。求出所有人中任何一个人赢得冠军所需要的最小胜场树数。(就是让你求这棵树的最小可能深度)
题解
显然根据谁被谁给淘汰的信息可以构建一棵树,那么一个人赢得所有人就是它的儿子。然后不就是一个傻逼贪心题了吗。设\(f[i]\)表示子树中任何一个点想要达到\(i\)这个位置最多需要赢得场次的最小值。显然按照所有儿子的\(f\)值排序然后贪心顺次选择即可。不懂看代码。
#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;
}
struct Line{int v,next;}e[MAX];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int n,f[MAX],S[MAX],top;
void dfs(int u)
{
for(int i=h[u];i;i=e[i].next)dfs(e[i].v);
top=0;
for(int i=h[u];i;i=e[i].next)S[++top]=f[e[i].v];
sort(&S[1],&S[top+1]);
for(int i=1;i<=top;++i)f[u]=max(f[u],S[i]+top-i+1);
}
int main()
{
n=read();
for(int i=2;i<=n;++i)Add(read(),i);
dfs(1);printf("%d\n",f[1]);
return 0;
}
C - Division into Two
翻译
题解
考虑一个\(O(n^2)\)的暴力,设\(f[i][j]\)表示第一个集合中的最后一个数是\(i\),第二个集合中的最后一个数是\(j\)的方案数,把所有数全部排序之后从前往后依次放就好了(事实上给定的数就是有序的)。
先不妨令\(A>B\),这样子如果存在三个元素两两之间的差都小于\(B\)显然就无解,直接判掉。直接判掉这种情况之后,对于较小的\(B\),显然有且仅有相邻的两个元素可能会出现不合法的情况了。
设\(f[i]\)表示第一个集合中最后一个选取的数是\(i\) 的方案数,考虑哪些\(j\)可以转移过来,首先\(j<i\)(废话),然后\(s[i]-s[j]\ge A\),并且\([j+1,i-1]\)这一段两两之差都大于等于\(B\)。显然\(j\)也是连续的一段,前缀和随便维护一下就好了。
太弱了,能够想到大部分就是最后的细节想不清
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
#define MOD 1000000007
#define MAX 100100
inline ll read()
{
ll 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 add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
int n,f[MAX],s[MAX];
ll A,B,a[MAX];
int main()
{
n=read();A=read();B=read();if(A>B)swap(A,B);
for(int i=1;i<=n;++i)a[i]=read();
for(int i=1;i<=n-2;++i)
if(a[i+2]-a[i]<A){puts("0");return 0;}
f[0]=s[0]=1;
for(int i=1,p=0,lim=0;i<=n;++i)
{
while(p<i&&a[i]-a[p+1]>=B)++p;
if(lim<=p)add(f[i],(s[p]+MOD-(lim?s[lim-1]:0))%MOD);
add(s[i],s[i-1]+f[i]);
if(i>1&&a[i]-a[i-1]<A)lim=i-1;
}
int ans=0;
for(int i=n;~i;--i)
{
add(ans,f[i]);
if(i<n&&a[i+1]-a[i]<A)break;
}
printf("%d\n",ans);
return 0;
}
D - Uninity
翻译
看半天看不懂系列。最后百度才知道什么意思。。。
类似点分治过程,只不过分治中心任意选择。 求点分树最小深度。
题解
毫无思路系列、不看题解不会做系列。
首先都说了类似于点分治的过程,那么加入我们直接搬点分治,这个答案不会超过\(log\)。然而对于直接做题没有太多的帮助。考虑这样一个性质,假设我们把这个点分树给构出来之后,有两个点的深度相同,都为\(K\),那么不难证明他们在原树中的路径上至少存在一个点满足深度小于\(K\)。现在把深度反过来看,即从叶子节点开始倒着填数,变成了任意两个权值相等的点的路径上都存在一个点的权值大于他们的权值,要求最小化最大权值。那么利用贪心考虑填数,因为答案不会超过\(log\),所以可以直接用一个二进制数把子树中拥有的、没有匹配上的每个权值的点个压一下。
#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<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int f[MAX][25];
int ans,n;
void dfs(int u,int ff)
{
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(v==ff)continue;
dfs(v,u);
for(int j=0;j<=20;++j)f[u][j]+=f[v][j];//统计儿子中所有未被匹配的每个标号的个数
}
int p=0;
for(int i=20;~i;--i)
if(f[u][i]>1){p=i+1;break;}//如果超过了两个,那么必须在LCA处匹配
while(f[u][p])++p;++f[u][p];//必须要找一个没有出现过的标号,否则儿子中的那个标号的LCA就是当前点
for(int i=0;i<p;++i)f[u][i]=0;//所有小于当前值的都匹配上了
ans=max(ans,p);
}
int main()
{
n=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read();
Add(u,v);Add(v,u);
}
dfs(1,0);printf("%d\n",ans);
return 0;
}
E - Eternal Average
翻译
黑板上有\(n\)个\(0\)和\(m\)个\(1\)。每次可以选择黑板上所有的数,然后选择\(K\)个,把他们擦掉,再把他们的平均数给写上去,问最终剩下的那一个数有多少种取值。保证\(n+m-1\)被\(K-1\)整除。
题解
我们把整个过程可以用一棵树来表示。显然这是一棵\(K\)叉树,有\(n+m\)个叶子,每个点的权值为所有儿子的权值的平均值。这样以来,我们可以分开考虑每一个叶子节点对于答案的贡献,显然,这个值是\(\sum k^{-dep}\),即所有权值为\(1\)的叶子节点的\(K\)的深度次方分之一的和。
那么,问题被转化成了,求有多少个\(z(0\lt z\lt 1)\)可以被拆分成恰好\(n\)个\(\frac{1}{k}\)的若干次幂。把\(01\)反过来考虑,同时\(1-z\)要能够被恰好拆分成\(m\)个\(\frac{1}{k}\)的若干次幂。反过来成立也很好证明,你先假装所有点的点权都是\(1\),那么根节点的值显然也是\(1\),那么\(\sum_{i=1}^nk^{-dep}+\sum_{i=1}^mk^{-dep}=1\),减一下显然成立。
考虑如何求解\(z\),首先\(z\)能够被分解成\(n\)个\(\frac{1}{k}\)的若干次幂。我们把\(z\)写成\(k\)进制的形式,假设其为\(z=0.c_1c_2...c_l\)。考虑\(\sum c_i\)和\(n\)之间的关系。如果没有进位的情况出现,那么显然\(\sum c=n\),如果出现了进位的情况,显然是低位减去了一个\(k\),然后高位加上了一个\(1\)。那么只需要\(\sum c \equiv n(mod\ k-1)\)就好了。\(1-z\)和\(m\)之间的关系同理。值得注意的一点是,在这个状态中\(c_l\)不能为零。
那么我们可以来搞\(dp\)了,设\(f[i][j]\)表示考虑了前\(i\)位(小数点后的位),他们的和是\(j\)的方案数。因为钦定最后一位不是\(0\),所以额外记录一下最后一个填的是不是零。
#include<iostream>
#include<cstdio>
using namespace std;
#define MOD 1000000007
#define MAX 2020
int f[MAX<<1][MAX][2],s[MAX],n,m,K,ans;
void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
int main()
{
cin>>n>>m>>K;m-=1;K-=1;
f[0][0][0]=1;
for(int i=1;i<=max(n,m)<<1;++i)
{
for(int j=0;j<=n;++j)s[j+1]=((s[j]+f[i-1][j][0])%MOD+f[i-1][j][1])%MOD;
for(int j=0;j<=n;++j)
{
f[i][j][0]=(s[j+1]-s[j]+MOD)%MOD;
int k=max(0,j-K);
f[i][j][1]=(s[j]-s[k]+MOD)%MOD;
}
for(int j=0;j<=n;++j)
if(j%K==n%K&&(i*K-j)%K==m%K&&i*K-j<=m)
add(ans,f[i][j][1]);
}
cout<<ans<<endl;
return 0;
}
AtCoder Grand Contest 009的更多相关文章
- AtCoder Grand Contest 009 D:Uninity
题目传送门:https://agc009.contest.atcoder.jp/tasks/agc009_d 题目翻译 定义只有一个点的树权值为\(0\),若干棵(可以是\(0\)棵)权值为\(k\) ...
- AtCoder Grand Contest 009 E:Eternal Average
题目传送门:https://agc009.contest.atcoder.jp/tasks/agc009_e 题目翻译 纸上写了\(N\)个\(1\)和\(M\)个\(0\),你每次可以选择\(k\) ...
- AtCoder Grand Contest 009 题解
传送门 为啥这场题目少一点啊-- \(A\) 易知增加的数前面肯定比后面大,那么我们倒着做,然后维护一下最小要加多少就可以了 typedef long long ll; const int N=1e5 ...
- 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 008
AtCoder Grand Contest 008 A - Simple Calculator 翻译 有一个计算器,上面有一个显示按钮和两个其他的按钮.初始时,计算器上显示的数字是\(x\),现在想把 ...
- AtCoder Grand Contest 007
AtCoder Grand Contest 007 A - Shik and Stone 翻译 见洛谷 题解 傻逼玩意 #include<cstdio> int n,m,tot;char ...
随机推荐
- 【本地服务器】json-server搭建本地https服务器(windows)
(一)用json-server搭建简单的服务器 (搭建出来的服务器地址为localhost:3000) 1.新建Mockjson文件夹,进入该文件夹目录,运行命令 npm install -g jso ...
- CF1039E Summer Oenothera Exhibition 根号分治,LCT,ST表
CF1039E Summer Oenothera Exhibition LG传送门 根号分治好题. 可以先看我的根号分治总结. 题意就是给出长度为\(n\)的区间和\(q\)组询问以及一个\(w\), ...
- VS编程,WPF中,获取鼠标相对于当前屏幕坐标的一种方法
原文:VS编程,WPF中,获取鼠标相对于当前屏幕坐标的一种方法 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/article/det ...
- 如何查看哪个进程,使用了哪个CPU
某些时候,我们需要知道,在Unix/Linux 环境中,CPU究竟消耗在了哪些进程上面. 如下是最简单的方法: ps -elF
- 阿里云Redis外网转发访问
1.前提条件 如果您需要从本地 PC 端访问 Redis 实例进行数据操作,可以通过在 ECS 上配置端口映射或者端口转发实现.但必须符合以下前提条件: 若 Redis 实例属于专有网络(VPC),E ...
- HDU-6356 Glad You Came (线段树)
题目链接:Glad You Came 题意:数组有n个数初始为0,m个询问,每个询问给出L R V(按照给定函数生成),将数组的下标L到R的数与V取较大值,最后输出给定的公式结果. 题意:哇~打比赛的 ...
- PowerBI开发 第一篇:设计PowerBI报表
PowerBI是微软新一代的交互式报表工具,把相关的静态数据转换为酷炫的可视化的,能够根据filter条件,对数据执行动态筛选,从不同的角度和粒度上分析数据.PowerBI主要由两部分组成:Power ...
- .Net-C#异步程序知识点梳理
:first-child{margin-top:0!important}.markdown-body>:last-child{margin-bottom:0!important}.markdow ...
- PAT甲题题解-1011. World Cup Betting (20)-误导人的水题。。。
题目不严谨啊啊啊啊式子算出来结果是37.975样例输出的是37.98我以为是四舍五入的啊啊啊,所以最后输出的是sum+0.005结果告诉我全部错误啊结果直接保留两位小数就可以了啊啊啊啊 水题也不要这么 ...
- C++ 实验 使用重载运算符实现一个复数类
实验目的: 1.掌握用成员函数重载运算符的方法 2.掌握用友元函数重载运算符的方法 实验要求: 1.定义一个复数类,描述一些必须的成员函数,如:构造函数,析构函数,赋值函数,返回数据成员值的函数等. ...