HGOI 20191108 题解
Problem A 新婚快乐
一条路,被$n$个红绿灯划分成$n+1$段,从前到后一次给出每一段的长度$l_i$,每走$1$的长度需要$1$分钟。
一开始所有红绿灯都是绿色的,$g$分钟后所有红绿灯变成红色,再过$r$分钟,所有红绿灯又重新变为绿色。
以$r+g$分钟为一个周期,如此反复。
有$Q$组询问,如果第$t_i$分钟从第一条线段的首端出发走到最后一条线段末端需要的时刻。
对于$100\%$的数据满足$1 \leq n\leq 2\times 10^5$ , 其他所有数字都在$10^9$以下。
Solution :
设$f[i]$表示第$i$个红绿灯恰好绿灯开始,走到最后的时间长度。
转移的话就是从最近的一个$j$(即编号最小),且满足$|s_j - s_i| \% (r+g) \geq g$。
这个时候,我们需要解这样一个带有取模运算的不等式,$(a+b)\% c \geq d$
我们打一个表发现,若$a=0$,答案显然是$[d,c-1]$,如果对于任意$1 \leq a < c$只要把答案区间往左平移$a$即可。
这个时候,可能出现段首一部分被覆盖,段尾一部分被覆盖。
直接用权值线段树维护位置信息即可。
最后计算答案的时候,也需要解这样一个不等式,类似的,计算出当前出发第一个遇到红灯的位置即可。
使用动态开点的权值线段树,可以实现时间复杂度$O(n log_2 S)$,其中$S$是值域。
# include <bits/stdc++.h>
# define int long long
# define root rt
# define inf (1e18)
using namespace std;
const int N=2e5+;
int n,g,r;
int s[N],f[N];
struct Seg {
int ls,rs,val;
Seg() { val = inf; ls=rs=; }
};
struct QwQ {
int root,tot;
QwQ () { root=;tot=;}
Seg tr[N*];
void insert(int &x,int l,int r,int pos,int val) {
if (!x) x=++tot;
if (l==r) { tr[x].val=val; return;}
int mid=(l+r)>>;
if (pos<=mid) insert(tr[x].ls,l,mid,pos,val);
else insert(tr[x].rs,mid+,r,pos,val);
tr[x].val=min(tr[tr[x].ls].val,tr[tr[x].rs].val);
}
int query(int x,int l,int r,int opl,int opr) {
if (!x) return inf;
if (opl<=l && r<=opr) return tr[x].val;
int ret=inf,mid=(l+r)>>;
if (opl<=mid) ret=min(ret,query(tr[x].ls,l,mid,opl,opr));
if (opr>mid) ret=min(ret,query(tr[x].rs,mid+,r,opl,opr));
return ret;
}
int query(int x) {
x=(x%(g+r)+(g+r))%(g+r);
if (g-x>=) return query(root,,g+r-,g-x,g+r--x);
else return min(query(root,,g+r-,,g+r--x),query(root,,g+r-,(g-x+g+r)%(g+r),g+r-));
}
}tr1,tr2;
signed main()
{
scanf("%lld%lld%lld",&n,&g,&r);
for (int i=;i<=n+;i++) {
int t; scanf("%lld",&t); s[i]=s[i-]+t;
}
f[n]=s[n+]-s[n]; tr1.insert(tr1.root,,g+r-,s[n]%(g+r),n);
for (int i=n-;i>=;i--) {
int j = tr1.query(g+r-s[i]%(g+r));
if (j == inf) {
f[i] = s[n+]-s[i];
} else {
f[i] = f[j] + (s[j]-s[i]) + g+r-(s[j]-s[i])%(g+r);
}
tr1.insert(tr1.root,,g+r-,s[i]%(g+r),i);
}
for (int i=;i<=n;i++) tr2.insert(tr2.root,,g+r-,s[i]%(g+r),i);
int q; scanf("%lld",&q);
while (q--) {
int t; scanf("%lld",&t);
int p = tr2.query(t%(g+r));
if (p == inf) { printf("%lld\n",t+s[n+]); continue;}
else {
printf("%lld\n",s[p]+t+g+r-(s[p]+t)%(g+r)+f[p]);
}
}
return ;
}
wedding.cpp
Problem B 能量传输
有$n$个人排成一圈,每恰好相隔$k$个人可以花费$1$的代价传输$1$的能量。
给出每个人的初始能量,为了使得每个人最终的能量都相等,输出最小代价。
对于$100\%$的数据满足$1 \leq k\leq n \leq 5 \times 10^5 $
Solution :
首先,本题每相邻$k$个人可进行交换,于是我们就可以做若干次环形均分纸牌即可。
环形均分纸牌问题,需要使用两个模型,第一个是线性的均分纸牌,另外一个是中位数。
设$s[i]$为数组的前缀和,这些数最终都变成$r = \frac{\sum\limits_{i=1}^{n}}{n}$
线性状态下 , 第$1$个人显然需要和第$2$进行交换,使得自己纸牌数成为$r$.
依次类推,在最优状态下,到第$i$个人和第$i+1$个人交换的时候,$|i \times r - s[i]|$是需要交换的总排数。
所有总交换次数就是$\sum\limits_{i=1}^{n} |i \times r - s[i]|$
为了计算方便,一开始,我们让所有数减去一个平均数$r$,并最终让所有人手中有0张牌,答案显然不变,就是$\sum |s_i|$了。
为了让线性变成环形,我们考虑一个较为朴素的做法,将$n$种断环方法,然后做一次均分纸牌即可。
继续推导,当前断环所成的东西是这样的。
// 设S[i]数组为减去avg的前缀和数组,显然有S[M]=0
A[k+] S[k+]-S[k]
A[k+] S[k+]-S[k+]
....
A[M] S[M] - S[k]
A[] S[]+S[M]-S[k]
...
A[k] S[k]+S[M]-S[k]
这个时候所需要的步数就是$\sum\limits_{i=1}^{n}|s[i] - s[k]|$,这个时候取$s[k]$为中位数的时候最小。
时间复杂度为$O(n log_2 n)$
# include <bits/stdc++.h>
# define int long long
using namespace std;
const int N=2e6+;
int a[N],b[N],g[N];
bool vis[N];
int cnt,n,k,sum;
int solve(int u) {
int cnt=;
for (int i=u;;i+=k) {
if (i>n) i-=n;
if (vis[i]) break;
vis[i]=; b[++cnt]=a[i]-sum;
}
for (int i=;i<=cnt;i++)
g[i]=g[i-]+b[i];
sort(g+,g++cnt);
int mid = g[(cnt+)/]; int ans=;
for (int i=;i<=cnt;i++) ans+=abs(g[i]-mid);
return ans;
}
signed main()
{
scanf("%lld%lld",&n,&k); k++;
for (int i=;i<=n;i++) {
scanf("%lld",&a[i]); sum+=a[i];
}
sum/=n; int ans=;
for (int i=;i<=n;i++) if (!vis[i]) {
ans+=solve(i);
}
printf("%lld\n",ans);
return ;
}
energy.cpp
Problem C 矿物运输
给出一棵有$n$个点的树,每一个点上面有一个权值$val_i$
先手和后手轮流操作,使得一个节点上$1$的权值移到它的父亲节点上、
无法移动的人判负,先手胜利输出"win"否则输出"lose"
对于$100\%$的数据满足$1 \leq n \leq 2 \times 10^5$
Solution :
这是是多个有向图游戏的和,而多个有向图(G)游戏的和SG函数值等于它包含的各个子游戏SG函数值的异或和,即SG(G) = SG(G1) xor SG(G2) xor SG(Gm)。
所以我们不妨将深度为奇数的所有点矿石数求异或,结果大于零(根据NIM游戏规则)则输出win(先手必胜),否则输出lose。
时间复杂度为$O(n)$
#include<bits/stdc++.h>
using namespace std; const int maxn=; struct Edge{
int next,to;
}edge[maxn]; int n,nedge,head[maxn],ans;
int a[maxn]; void addedge(int a,int b){
edge[nedge].next=head[a];
edge[nedge].to=b;
head[a]=nedge++;
} void dfs(int u,int d){
if (d%==) ans^=a[u];
for (int i=head[u];i!=-;i=edge[i].next){
int v=edge[i].to;
dfs(v,d+);
}
} int main(){ int cas;
scanf("%d",&cas);
while(cas--){
scanf("%d",&n);
nedge=,ans=;
memset(head,-,sizeof(head));
for (int i=;i<n;i++){
int k;
scanf("%d",&k);
addedge(k,i);
}
for (int i=;i<n;i++) scanf("%d",&a[i]);
dfs(,);
if (!ans) puts("lose");
else puts("win");
}
return ;
}
ore.cpp
HGOI 20191108 题解的更多相关文章
- HGOI 20181028 题解
HGOI 20181028(复赛备考) /* 真是暴力的一天,最后一题MLE?由于数组开得太大了!!! 270滚粗 考场上好像智商高了很多?!(假的) */ sol:暴力求解,然后没有数据范围吐槽一下 ...
- HGOI 20190310 题解
/* 又是又双叒叕WA的一天... 我太弱鸡了... 今天上午打了4道CF */ Problem 1 meaning 给出q组询问,求下列函数的值$ f(a) = \max\limits_{0 < ...
- HGOI 20190303 题解
/* 记一串数字真难. 5435 今天比赛又是hjcAK的一天. 今天开题顺序是312,在搞T1之前搞了T3 昨天某谷月赛真是毒瘤. 但是讲评的同学不错,起码T4看懂了... 构造最优状态然后DP的思 ...
- HGOI 20180224 题解
/* The Most Important Things: ljc chat with fyh on QQTa说期末考Ta数学74分感觉不好但是我觉得fyh是地表最强的鸭~~(of course en ...
- HGOI 20190218 题解
/* 又是AK局... hjc又双叒叕AK了... Hmmm...我侥幸 */ Problem A card 给出无序序列a[]可以选择一个数插入到合适的位置作为一次操作,至少多少次操作后可以把序列变 ...
- HGOI 20190217 题解
/* for me,开训第一天 /beacuse 文化课太差被抓去补文化课了... 看一眼题 : AK局? 但是,Wa on test #10 in problem C 290! (就差那么一咪咪) ...
- HGOI 20181103 题解
problem:把一个可重集分成两个互异的不为空集合,两个集合里面的数相乘的gcd为1(将集合中所有元素的质因数没有交集) solution:显然本题并不是那么容易啊!考场上想了好久.. 其实转化为上 ...
- HGOI 20181101题解
/* 又是爆0的一天(不知道今年高考难不难,反正今天(信息学)真的难!) */ solution:对于两个数相加,有一个显然的结论就是要么不进位(相对于位数大的),要么(进最多一位) 然后对于整个数组 ...
- HGOI 20191107 题解
Problem A 树状数组 给出下列$C++$代码: 设区间加操作$modify(l,r)$为调用两次$update(r,1)$和$update(l-1,-1)$ 设$f(l,r)$表示在初始$cn ...
随机推荐
- Tkinter(一)
采集小工具,目前采集主要针对知乎文章与评论,今天刚开始弄,会不断更新完善 目前效果(测试站点 :科技:测试连接:http://zhihu.sogou.com/include/pc/pc/topic/t ...
- Python何时执行装饰器
装饰器的一个关键特性是,它们在被装饰的函数定义之后立即运行.这 通常是在导入时(即 Python 加载模块时),如示例 7-2 中的 registration.py 模块所示. 示例 7-2 regi ...
- spark调优篇-spark on yarn web UI
spark on yarn 的执行过程在 yarn RM 上无法直接查看,即 http://192.168.10.10:8088,这对于调试程序很不方便,所以需要手动配置 配置方法 1. 配置 spa ...
- WPF入门(3)——命令
命令是ICommand类型的属性,binding到控件上,用于代替事件,个人认为事件也很好,命令只是轻度解耦前后端. 闲话少说,上代码,示例是ScreenToGif的源代码中的一个命令: public ...
- PB各对象常用事件
1.window中的事件 事件名 触发的时机 01.Activate 在窗口激活之前触发 02.Clicked 当用户用 ...
- Unity上线google商店 用IL2Cpp打包64位版本和Android APP Bundle优化 及产生的bug
ios刚上线,这边着手改成android版本,我开始使用的是unity2017.4.1版本 上传谷歌商店是出现这两个警告: 要支持64位,但是在2017版本上没有找到64位的打包选项,猜测应该是版本的 ...
- [JZOJ100026]图--倍增
[JZOJ100026]图--倍增 题目链接 太懒了,自行搜索 分析 裸倍增,不多说 \(fa[i][j]\)表示\(i\)跳\(2^j\)步走到的点 \(f[i][j]\)表示\(i\)跳\(2^j ...
- Web Api 将DataTable装换成Excel,并通过文件流将其下载
不废话,直接上代码 前端代码 <input type="button" class="layui-btn" value="Test-GetFil ...
- IDEA GIT 忽略文件
1.装插件 .igore 2.新建忽略文件格式 3.编辑忽略后缀文件 可以是文件夹 也可以是 具体文件类型
- ASE19团队项目alpha阶段model组 scrum6 记录
本次会议于11月8日,19时整在微软北京西二号楼sky garden召开,持续15分钟. 与会人员:Kun Yan, Lei Chai, Linfeng Qi, Xueqing Wu, Yutong ...