HGOI20190810 省常中互测3
Problem A 夏洛特
若当前处在点$(x,y)$下一时刻可以向该点四周任意方向走动一步,
初始在$(0,0)$是否存在一条合法的路线满足下列$n$个限制:
每一个限制形如$t_i , x_i , y_i$表示第$t_i$时刻,需要在点$(x_i , y_i)$ 处
输出"YES"或者"NO",有$T(T\leq 10)$组数据。
对于$100\%$的数据满足$n \leq 10^5 ,0 \leq x_i,y_i \leq 10^5 , 0 \leq t_i \leq 10^7$
Sol: 首先按照时间先后排序,每次考虑从$t_0 , x_0 ,y_0$的限制走到$t , x, y$的限制、
显然,从$(x_0,y_0)$走到$(x,y)$至少需要$|x-x_0|+|y-y_0|$步,
于是令$res = t - t_0 - (|x-x_0|+|y-y_0|)$ 表示剩余需要浪费的步数。
显然,如果剩余步数为偶数那么可以上下、上下的构造出合法解,若剩余步数为奇数则没有办法构造。
上述算法的复杂度是$O(T n \ log_2 n)$
# include <bits/stdc++.h>
# define int long long
using namespace std;
const int N=2e5+;
struct rec{
int t,x,y;
}a[N];
int n;
bool cmp(rec a,rec b){return a.t<b.t;}
bool work()
{
int t=0ll,x=0ll,y=0ll;
for (int i=;i<=n;i++) {
int res=a[i].t-t-abs(a[i].x-x)-abs(a[i].y-y);
if ((res < 0ll) || (res & 1ll)) return false;
t=a[i].t; x=a[i].x; y=a[i].y;
}
return true;
}
inline int read()
{
int X=,w=; char c=;
while(c<''||c>'') {w|=c=='-';c=getchar();}
while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
return w?-X:X;
}
signed main()
{
freopen("charlotte.in","r",stdin);
freopen("charlotte.out","w",stdout);
int T=read();
while (T--) {
n=read();
for (int i=;i<=n;i++) a[i].t=read(),a[i].x=read(),a[i].y=read();
sort(a+,a++n,cmp);
puts(work()?"Yes":"No");
}
return ;
}
A.cpp
Problem B 西比拉先知系统
给出一幅无向图$G$,初始每个点的点权为$0$,维护下面$2$个操作:
0 x : 表示询问点$x$的点权。
1 x y : 表示将点$x$和与点$x$直接相连的点权加上$y$
Subtask1 :任意两个点之间一定定满足不连通或存在恰好一条路径
Subtask2:除了1号节点以外,所有节点度数小于$10$
对于$100\%$的数据,$n,m,Q \leq 3\times 10^5 , y \leq 10^3$
Sol: 考场没$A$,被卡常了,$95 \ pts$
考虑部分分怎么做,
Subtask1 : 保证$G$是森林 , 对每一棵树求出bfs序,使得直接儿子的编号是连续的。
由于父亲只有一个,那么在加权的时候再额外的把父亲的权加上即可。
树状数组维护区间加,单点求值。 复杂度是$O(m \ log_2 n)$
Subtask2 : 对于$1$号节点稍微特判一下,若不是一号节点的进行操作$2$直接暴力。
如果是$1$号节点进行操作$2$那么只需要打一个标记即可.
对于询问操作,如果这个点是$1$或者与$1$直接相连那么除了自己维护的那个真实值以外还需要加上$1$节点的标记值。
这样的复杂度是$O(10 \times m)$
然后这样就可以写出$73 \ pts $的代码了。
# include<bits/stdc++.h>
using namespace std;
int n,m,q;
vector<int>E[];
inline int read()
{
int X=,w=; char c=;
while(c<''||c>'') {w|=c=='-';c=getchar();}
while(c>=''&&c<='') X=(X<<)+(X<<)+(c^),c=getchar();
return w?-X:X;
}
void write(int x)
{
if (x<) putchar('-'),x=-x;
if (x>) write(x/);
putchar(''+x%);
}
void writeln(int x)
{
write(x); putchar('\n');
}
bool vis[],flag;
void cir(int u,int fa)
{
vis[u]=;
for (int i=;i<(int)E[u].size();i++) {
int v=E[u][i]; if (v==fa) continue;
if (vis[v]) { flag=; return;}
cir(v,u);
}
}
bool check1()
{
memset(vis,false,sizeof(vis));
for (int i=;i<=n;i++)
if (!vis[i]) {
flag=; cir(i,);
if (!flag) return false;
}
return true;
} namespace Subtask1 {
const int N=3e3+;
int val[N];
void update(int u,int value)
{
val[u]+=value;
for (int i=;i<(int)E[u].size();i++) {
int v=E[u][i];
val[v]+=value;
}
}
void main() {
memset(val,,sizeof(val));
for (int i=;i<=q;i++) {
int op=read(),x=read();
if (op) { int y=read(); update(x,y);}
else writeln(val[x]);
}
exit();
}
}
namespace Subtask2 {
const int N=3e5+;
int bfsn[N],c[N],R[N],f[N];
# define lowbit(x) (x&(-x))
void update(int x,int d) { for (;x<=bfsn[];x+=lowbit(x)) c[x]+=d;}
void modify(int l,int r,int d){update(l,d); update(r+,-d);}
int query(int x) { int ret=; for (;x;x-=lowbit(x)) ret+=c[x]; return ret;}
# undef lowbit
void bfs(int u,int fa) {
f[u]=fa; R[u]=bfsn[u];
for (int i=;i<(int)E[u].size();i++) {
int v=E[u][i]; if (v==fa) continue;
bfsn[v]=++bfsn[];
R[u]=bfsn[v];
}
for (int i=;i<(int)E[u].size();i++) {
int v=E[u][i]; if (v==fa) continue;
bfs(v,u);
}
}
void main() {
memset(bfsn,,sizeof(bfsn));
for (int i=;i<=n;i++)
if (!bfsn[i]) bfsn[i]=++bfsn[],bfs(i,);
for (int i=;i<=q;i++) {
int op=read(),x=read();
if (op) {
int y=read();
if (f[x]) {
modify(bfsn[f[x]],bfsn[f[x]],y);
}
modify(bfsn[x],R[x],y);
} else writeln(query(bfsn[x]));
}
}
}
namespace Subtask3 {
const int N=3e5+;
int add,val[N];
bool mark[N];
void update(int u,int value) {
val[u]+=value;
for (int i=;i<(int)E[u].size();i++) {
int v=E[u][i];
val[v]+=value;
}
}
void main() {
for (int i=;i<(int)E[].size();i++) mark[E[][i]]=;
for (int i=;i<=q;i++) {
int op=read(),x=read();
if (op) {
int y=read();
if (x==) val[]+=y,add+=y;
else update(x,y);
} else writeln(val[x]+(mark[x]?add:));
}
}
}
int main()
{
n=read();m=read();q=read();
for (int i=;i<=m;i++) {
int u=read(),v=read();
if (u==v) continue;
E[u].push_back(v);
E[v].push_back(u);
}
for (int i=;i<=n;i++) {
sort(E[i].begin(),E[i].end());
E[i].erase(unique(E[i].begin(),E[i].end()),E[i].end());
}
if (n<= && m<= && q<=) Subtask1::main();
else if (check1()) Subtask2::main();
else Subtask3::main();
return ;
}
B_73pts.cpp
现在来考虑正解,试图推广一下Subtask2的做法,如果一个点进行了操作$1$,事实上我们不需要将所有和它相连的边都跑过去,而是使用一个$tag$标记来记录一下这个点被加了多少。
把原来的无向图看成有向图,对于原来所有无向边,转化为度较小的点向度较大的点连单向边。
对于一个$1$操作我们只需要将当前点的$tag$标记加上,然后把单向边中它指向的节点的val值更新即可。
对于一个$0$操作我们只需要将该点指向的所有元素的$tag$加上然后加上该点的$val$值即可。
对于一次操作,复杂度应该为两个点之间的较小的度。这个东西当完全图的时候可以最大化,所以极限是$\sqrt{n}$
综上所述,我们的算法的复杂度是$O(m \sqrt{n})$ ,并且是一个极其不满的上界。
# include <bits/stdc++.h>
using namespace std;
const int N=3e5+;
struct edge{
int u,v;
}e[N];
int n,m,q,val[N],du[N],tag[N];
vector<int>E[N];
int main()
{
scanf("%d%d%d",&n,&m,&q);
for (int i=;i<=m;i++)
scanf("%d%d",&e[i].u,&e[i].v),
du[e[i].u]++,du[e[i].v]++;
for (int i=;i<=m;i++)
if (du[e[i].u]<du[e[i].v]) E[e[i].u] .push_back(e[i].v);
else E[e[i].v] .push_back(e[i].u);
while (q--) {
int op,x; scanf("%d%d",&op,&x);
if (op==) {
int ret=val[x];
for (int i=;i<E[x].size();i++) {
int v=E[x][i]; ret+=tag[v];
}
printf("%d\n",ret);
} else {
int y; scanf("%d",&y);
for (int i=;i<E[x].size();i++) {
int v=E[x][i]; val[v]+=y;
}
val[x]+=y; tag[x]+=y;
}
}
return ;
}
B.cpp
Problem C 替身使者
给出一个$5$次多项式$G(x) = \sum\limits_{i=1} ^ 5 a_i \times x^i $
其第$i$次项的系数$a_i$满足$0 \leq a_i \leq 10$
给出若干条线段$[l_i,r_i] , 1 \leq l_i \leq r_i \leq m$,可以在这些线段中的任意一个点放一个替身使者。
最大化每个点G(替身使者数目)的和。
对于$100 \%$ 的数据$1 \leq m \leq 10^7 , 1 \leq n \leq 250$
Sol : 观察到线段的长度和答案没有任何关系,离散化即可。
值域为$[1,500]$,设$f[l][r]$表示在值域$[l,r]$的答案为多少。
那么显然设$T$为值域右边界,答案就是$f[1][T]$
区间dp,设在第$i$个位置放尽可能多的替身使者,问题就转化为两个子问题$f[l][i-1] , f[i+1][r]$
这样子增加的贡献值就是$G(num_i)$ ,复杂度是$O(n^3)$
# include <bits/stdc++.h>
# define int long long
using namespace std;
const int N=;
struct rec{ int l,r;}a[N];
int f[N][N],n,m,v[],c[N],T;
vector<int>t;
int fun(int x){return v[]*x+v[]*x*x+v[]*x*x*x+v[]*x*x*x*x+v[]*x*x*x*x*x;}
int dfs(int l,int r)
{
if (l>r) return ;
if (f[l][r]!=-) return f[l][r];
vector<int>v; v.resize(r-l+);
for (int i=;i<=n;i++)
if (a[i].l>=l && a[i].r <= r) {
v[a[i].l-l]++;
if (a[i].r<r)v[a[i].r-l+]--;
}
int ans=,now=;
for (int i=;i<r-l+;i++) {
now+=v[i];
ans=max(ans,dfs(l,l+i-)+dfs(l+i+,r)+fun(now));
}
return f[l][r]=ans;
}
signed main()
{
scanf("%lld%lld",&n,&m);
for (int i=;i<;i++) scanf("%lld",&v[i]);
for (int i=;i<=n;i++) {
scanf("%lld%lld",&a[i].l,&a[i].r);
t.push_back(a[i].l); t.push_back(a[i].r);
}
sort(t.begin(),t.end());
T=unique(t.begin(),t.end())-t.begin();
for (int i=;i<=n;i++)
a[i].l=lower_bound(t.begin(),t.begin()+T,a[i].l)-t.begin()+,
a[i].r=lower_bound(t.begin(),t.begin()+T,a[i].r)-t.begin()+;
memset(f,-,sizeof(f));
int ans = dfs(,T);
printf("%lld\n",ans);
return ;
}
C.cpp
HGOI20190810 省常中互测3的更多相关文章
- HGOI 20190816 省常中互测8
Problem A 有两条以(0,0)为端点,分别经过(a,b),(c,d)的射线,你要求出夹在两条射线中间,且距离(0,0)最近的点(x,y) 对于$100\%$的数据满足$1 \leq T \l ...
- HGOI20190814 省常中互测7
Problem A 中间值 对于$2$个非严格单增序列$\{A_n\} , \{B_n\}$,维护下列两个操作: 1 x y z: (x=0)时将$A_y = z$ , (x=1)时将$B_y = z ...
- HGOI20190813 省常中互测6
Problem A 蛋糕 将$n \times m $大小的蛋糕切成每块为$1 \times 1$大小的$n\times m$块. 交换任意两块蛋糕的切割顺序的方案算作一种. 对于$100 \%$的数 ...
- HGOI20190811 省常中互测4
Problem A magic 给出一个字符串$S$,和数字$n$,要求构造长度为$n$只含有小写字母的字符串$T$, 使得在$T$中存在删除且仅删除一个子串使得$S=T$成立. 输出$T$的构造方案 ...
- HGOI20190809 省常中互测2
Problem A 时之终结 构造一个含有$n$个节点的无重边无自环的有向图, 使得从$1$出发,每一次经过一条$(u,v) (u < v)$的边到达节点$n$的方案恰好有$y$种. 对于$10 ...
- HGOI20190808 省常中互测1
Problem A sum 给出$n$个元素的序列$\{a_i\}$,求出两个不相交连续子序列的最大元素和. 即对于$1 \leq A \leq B \leq C \leq D \leq n$最大化 ...
- HGOI20190812 省常中互测5
Task 1 辩论 有N 个参加辩论的候选人,每个人对这两个议题都有明确的态度,支持或反对.作为组织者,小D 认真研究了每个候选人,并给每个人评估了一个非负的活跃度,他想让活跃度之和尽可能大.选出的候 ...
- 【2018集训队互测】【XSY3372】取石子
题目来源:2018集训队互测 Round17 T2 题意: 题解: 显然我是不可能想出来的……但是觉得这题题解太神了就来搬(chao)一下……Orzpyz! 显然不会无解…… 为了方便计算石子个数,在 ...
- 【CH 弱省互测 Round #1 】OVOO(可持久化可并堆)
Description 给定一颗 \(n\) 个点的树,带边权. 你可以选出一个包含 \(1\) 顶点的连通块,连通块的权值为连接块内这些点的边权和. 求一种选法,使得这个选法的权值是所有选法中第 \ ...
随机推荐
- Oracle Help 类
public static string ConnString = @"Data Source=xxx;USER ID=xxx;PASSWORD=xxx"; /// <sum ...
- JS基础_强制类型转换-String
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- yii自定义验证
自定义验证类 class BaseModel extends Model { public function rules() { return [ ['obj', ContentSecurityVal ...
- Vue中如何插入m3u8格式视频,3分钟学会!
大家都知道video只支持ogg.webm.MP4格式,但是要是m3u8格式的视频怎么办?最近遇到这个问题在网上找了好多办法都不行,最后找到video.js后才完美解决,所以决定写一 ...
- MySQL 下载与安装
从MySQL官网下载安装文件,我的电脑是window10 64位的,下载社区版本,选择mysql community server,再下载64位的. 官网链接:https://www.mysql.co ...
- LeetCode——等差数列划分
题目: 如果一个数列至少有三个元素,并且任意两个相邻元素之差相同,则称该数列为等差数列. 例如,以下数列为等差数列: 1, 3, 5, 7, 97, 7, 7, 73, -1, -5, -9 以下数列 ...
- (转)Java8内存模型-永久代(PermGen)和元空间(Metaspace)
原文链接:https://www.cnblogs.com/paddix/p/5309550.html 一.JVM内存模型 根据jvm规范,jvm内存共分为虚拟机栈.堆.方法区.程序计算器.本地方法栈五 ...
- ffmpeg3.3.2命令行参数笔记
组成: 1.libavformat:用于各种音视频封装格式的生成和解析,包括获取解码所需信息以生成解码上下文结构和读取音视频帧等功能,包含demuxers和muxer库: 2.libavcodec:用 ...
- 韦东山嵌入式Linux学习笔记07--Nandflash
常用的flash有两种, Norflash和Nandflash, 前几年市场上的产品比较常见的方案时Norflash和Nandflash搭配使用, 因为norflash比较昂贵,相同的容量norfla ...
- Idea 汉化后定位和系统设置打不开到问题
百度网盘:此汉化包已经修正过,拿来直接可以用 链接:https://pan.baidu.com/s/1wm3NbYSM9Gtsdu2EHQPMIA 密码:qdr3 1.系统设置(setting)外观选 ...