GX/GZOI2019 day2 解题报告

题目链接

逼死强迫症

旅行者

旧词

t1 逼死强迫症

显然地,记 \(f(i)\) 为长度为 \(i\) 的木板的答案,可得: \(\\\)

\[f(i)=\begin{cases}
0 \quad ······························ \quad (i \in [0,2]) \\
f(i-1)+f(i-2)+2 \times pre(i-3) \quad ·· \quad ( i \in [3,+\infty]))
\end{cases}\]

其中 \(pre(n)=\Sigma_{i=0}^n fib(i)\);

然后矩阵快速幂就行了,复杂度 \(O(T \times 5^3 \times log_2n)\)。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long ll;
int in() {
int x=0;char c=getchar();bool f=false;
while(c<'0'||c>'9') f|=c=='-', c=getchar();
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48), c=getchar();
return f?-x:x;
} const int mod = 1e9+7; inline void add(int &x, int y) { x+=y; if(x>=mod) x-=mod; }
inline void sub(int &x, int y) { x-=y; if(x<0) x+=mod; } struct matrix {
int a[5][5]; matrix(int x=0) {
memset(a, 0, sizeof(a));
if(x) for(int i=0;i<5;++i) a[i][i]=x;
} inline int * operator [] (const int x) {
return a[x];
} inline matrix operator * (matrix b) const {
matrix ret;
for(int i=0;i<5;++i)
for(int j=0;j<5;++j)
for(int k=0;k<5;++k)
add(ret[i][j], (ll)a[i][k]*b[k][j]%mod);
return ret;
}
}; matrix qpow(matrix base, int b) {
matrix ret(1);
for(;b;b>>=1, base=base*base)
if(b&1) ret=ret*base;
return ret;
} int main() { //freopen("obsession.in", "r", stdin);
//freopen("obsession.out", "w", stdout); int T=in(), n; while(T--) {
n=in();
if(n<=2) {
puts("0");
continue;
}
matrix a, b;
a[0][0]=2, a[0][1]=0, a[0][2]=2, a[0][3]=1, a[0][4]=1; b[0][0]=1, b[0][1]=1;
b[1][0]=1;
b[2][0]=2, b[2][2]=1;
b[3][2]=1, b[3][3]=1, b[3][4]=1;
b[4][2]=1, b[4][3]=1; a=a*qpow(b, n-3); printf("%d\n", a[0][0]);
} return 0;
}

t2 旅行者

可以正向/反向建边,跑两遍 \(dijkstra\),染色(颜色为 \(k\) 个节点的编号),只有两边的颜色不同才造成贡献。这里没有写

有一种比较暴力的想法:

新建两个节点 \(S,T\),将 \(k\) 个点分成两组,\(S\) 向一组连边,另一组向 \(T\) 连边,边权都为 \(0\),跑最短路即可;

不难想到按二进制分组:枚举 \(k\) 的每一个二进制位,分成两组,做 \(log_2k\) 次。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
typedef long long ll;
typedef std::pair<ll, int> pli;
int in() {
int x=0;char c=getchar();bool f=false;
while(c<'0'||c>'9') f|=c=='-', c=getchar();
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48), c=getchar();
return f?-x:x;
}
template<typename T>inline void chk_min(T &_, T __) { _=_<__?_:__; } const int N = 1e5+5; struct edge {
int next, to, w;
}e[N*6];
int cnt, head[N]; int a[N]; ll d[N]; bool vis[N]; inline void jb(const int u, const int v, const int w) {
e[++cnt]=(edge){head[u], v, w}, head[u]=cnt;
} std::priority_queue <pli> q;
ll dijkstra(const int s, const int t) {
memset(d, 0x3f, sizeof(d));
memset(vis, 0, sizeof(vis));
q.push(pli(0, s));
d[s]=0;
while(!q.empty()) {
int u=q.top().second; q.pop();
if(vis[u]) continue;
vis[u]=1;
for(int i=head[u];i;i=e[i].next) {
int v=e[i].to, w=e[i].w;
if(d[u]+w<d[v]) {
d[v]=d[u]+w;
q.push(pli(-d[v], v));
}
}
}
return d[t];
} ll spfa_(const int s, const int t) {
memset(d, 0x3f, sizeof(d));
q.push(pli(0, s));
d[s]=0, vis[s]=1;
while(!q.empty()) {
int u=q.top().second; q.pop();
vis[u]=0;
for(int i=head[u];i;i=e[i].next) {
int v=e[i].to, w=e[i].w;
if(d[u]+w<d[v]) {
d[v]=d[u]+w;
if(!vis[v])
q.push(pli(-d[v], v)), vis[v]=true;
}
}
}
return d[t];
} std::deque <int> Q;
ll spfa(const int s, const int t) {
memset(d, 0x3f, sizeof(d));
Q.push_back(s);
d[s]=0, vis[s]=1;
while(!Q.empty()) {
int u=Q.front(); Q.pop_front();
vis[u]=0;
for(int i=head[u];i;i=e[i].next) {
int v=e[i].to, w=e[i].w;
if(d[u]+w<d[v]) {
d[v]=d[u]+w;
if(!vis[v]) {
if(Q.empty()) Q.push_back(v);
else if(d[Q.front()]<d[v]) Q.push_back(v);
else Q.push_front(v);
vis[v]=true;
}
}
}
}
return d[t];
} inline void init() {
cnt=1;
memset(head, 0, sizeof(head));
} int main() {
//freopen("tourist.in", "r", stdin);
//freopen("tourist.out", "w", stdout);
int T=in();
while(T--) {
int n=in(), m=in(), k=in();
init();
for(int i=1, x, y, z;i<=m;++i) {
x=in(), y=in(), z=in();
jb(x, y, z);
}
for(int i=1;i<=k;++i) a[i]=in(); int s=0, t=n+1;
ll res=1ll<<60ll;
for(int l=1;l<=k;l<<=1) {
for(int i=1;i<=k;++i)
if(i&l) jb(s, a[i], 0);
else jb(a[i], t, 0);
chk_min(res, spfa(s, t));
for(int i=1;i<=k;++i)
if(i&l) head[s]=e[head[s]].next, --cnt;
else head[a[i]]=e[head[a[i]]].next, --cnt; for(int i=1;i<=k;++i)
if(!(i&l)) jb(s, a[i], 0);
else jb(a[i], t, 0);
chk_min(res, spfa(s, t));
for(int i=1;i<=k;++i)
if(!(i&l)) head[s]=e[head[s]].next, --cnt;
else head[a[i]]=e[head[a[i]]].next, --cnt;
}
printf("%lld\n", res);
}
return 0;
}

t3 旧词

先考虑 \(k=1\) 的做法;

显然地,要离线处理,按 \(x\) 排好序,每一次把 \(1\)~\(x\) 的贡献维护好;

主要思想:对于深度为 \(d\) 的节点 \(u\),把 \(d\) 均摊到 \(1\)~\(u\) 这条链上,查询 \(y\) 时计算 \(1\)~\(y\) 的和即可。

如果 \(k=1\),则每次修改只需把 \(1\)~\(x\) 的权值每次加 \(1\)。

同样地,当 \(k \ne 1\) 时,不难发现,给每个节点一个权值(设点为 \(u\)) \((dep_u)^k-(dep_u-1)^k\),每次修改只需要加一次这个权值就行了。

树剖维护即可。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long ll;
int in() {
int x=0;char c=getchar();bool f=false;
while(c<'0'||c>'9') f|=c=='-', c=getchar();
while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48), c=getchar();
return f?-x:x;
}
const int N = 5e4+5, mod = 998244353; struct edge {
int next, to;
}e[N];
int cnt=1, head[N], dep[N], fro[N], siz[N], hson[N], dfn[N], pos[N], fa[N];
int n, m, k; //heavy-light decomposition begin
void dfs_h(const int u) {
siz[u]=1;
for(int i=head[u];i;i=e[i].next) {
int v=e[i].to;
dep[v]=dep[u]+1;
fa[v]=u;
dfs_h(v);
siz[u]+=siz[v];
if(siz[v]>siz[hson[u]]) hson[u]=v;
}
} void dfs_f(const int u, const int tp) {
fro[u]=tp, dfn[u]=++dfn[0], pos[dfn[u]]=u;
if(hson[u]) dfs_f(hson[u], tp);
for(int i=head[u];i;i=e[i].next)
if(e[i].to!=hson[u])
dfs_f(e[i].to, e[i].to);
} inline void prep() {
dep[1]=1;
dfs_h(1);
dfs_f(1, 1);
}
//heavy-light decomposition end //segment_tree begin inline void add(int &_, int __) { _+=__; if(_>=mod) _-=mod; } int qpow(int base, int b) {
int ret=1;
for(;b;b>>=1, base=(ll)base*base%mod)
if(b&1) ret=(ll)ret*base%mod;
return ret;
} struct segment_tree {
#define lson tl, mid, p<<1
#define rson mid+1, tr, p<<1|1
int t[N<<2], base[N<<2], lazy[N<<2];
inline void push_up(const int p) {
t[p]=t[p<<1]+t[p<<1|1];
if(t[p]>=mod) t[p]-=mod;
}
inline void spread(const int p) {
add(t[p<<1], (ll)base[p<<1]*lazy[p]%mod);
add(t[p<<1|1], (ll)base[p<<1|1]*lazy[p]%mod);
add(lazy[p<<1], lazy[p]), add(lazy[p<<1|1], lazy[p]);
lazy[p]=0;
}
void build(const int tl, const int tr, const int p) {
if(tl==tr) {
base[p]=qpow(dep[pos[tl]], k)-qpow(dep[pos[tl]]-1, k);
if(base[p]<0) base[p]+=mod;
return ;
}
int mid=(tl+tr)>>1;
build(lson), build(rson);
base[p]=base[p<<1]+base[p<<1|1];
if(base[p]>=mod) base[p]-=mod;
}
void update(const int l, const int r, const int tl, const int tr, const int p) {
if(l<=tl&&tr<=r)
return (void)(add(t[p], base[p]), add(lazy[p], 1));
int mid=(tl+tr)>>1;
if(lazy[p]) spread(p);
if(mid>=l) update(l, r, lson);
if(mid<r) update(l, r, rson);
push_up(p);
}
int query(const int l, const int r, const int tl, const int tr, const int p) {
if(l<=tl&&tr<=r) return t[p];
int mid=(tl+tr)>>1, ret=0;
if(lazy[p]) spread(p);
if(mid>=l) ret=query(l, r, lson);
if(mid<r) add(ret, query(l, r, rson));
return ret;
}
#undef lson
#undef rson
}T;
//segment_tree end struct ask {
int x, y, id;
}q[N];
int res[N]; inline bool cmpx(const ask &a, const ask &b) {
return a.x < b.x;
} void update(int u, int v) {
while(fro[u]!=fro[v]) {
if(dep[fro[u]]>dep[fro[v]]) std::swap(u, v);
T.update(dfn[fro[v]], dfn[v], 1, n, 1);
v=fa[fro[v]];
}
if(dep[u]>dep[v]) std::swap(u, v);
T.update(dfn[u], dfn[v], 1, n, 1);
} int query(int u, int v) {
int ret=0;
while(fro[u]!=fro[v]) {
if(dep[fro[u]]>dep[fro[v]]) std::swap(u, v);
add(ret, T.query(dfn[fro[v]], dfn[v], 1, n, 1));
v=fa[fro[v]];
}
if(dep[u]>dep[v]) std::swap(u, v);
add(ret, T.query(dfn[u], dfn[v], 1, n, 1));
return ret;
} int main() {
//freopen("poetry.in", "r", stdin);
//freopen("poetry.out", "w", stdout);
n=in(), m=in(), k=in();
for(int i=2;i<=n;++i) {
int f=in();
e[++cnt]=(edge){head[f], i};
head[f]=cnt;
}
prep();
T.build(1, n, 1); for(int i=1;i<=m;++i) q[i]=(ask){in(), in(), i};
std::sort(q+1, q+1+m, cmpx); for(int i=1, now=0;i<=m;++i) {
while(now<q[i].x) {
++now;
update(1, now);
}
res[q[i].id]=query(1, q[i].y);
} for(int i=1;i<=m;++i) printf("%d\n", res[i]);
return 0;
}

GX/GZOI2019 day2 解题报告的更多相关文章

  1. 【NOIP2015】提高day2解题报告

    题目: P1981跳石头 描述 一年一度的“跳石头”比赛又要开始了!这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之间,有 N ...

  2. 【未完成0.0】Noip2012提高组day2 解题报告

    第一次写一套题的解题报告,感觉会比较长.(更新中Loading....):) 题目: 第一题:同余方程 描述 求关于x的同余方程ax ≡ 1 (mod b)的最小正整数解. 格式 输入格式 输入只有一 ...

  3. NOIp2016 Day1&Day2 解题报告

    Day1 T1 toy 本题考查你会不会编程. //toy //by Cydiater //2016.11.19 #include <iostream> #include <cstd ...

  4. 常州培训 day2 解题报告

    第一题: 题目大意: 给出一个M面的骰子,投N次,求最大期望值. 最大期望值的定义: 比如M=2,N=2, 那么 2次可以是 1,1,最大值为1: 1,2最大值为2: 2,1最大值为2: 2,2 最大 ...

  5. NOIP2018提高组Day2 解题报告

    前言 关于\(NOIP2018\),详见此博客:NOIP2018学军中学游记(11.09~11.11). \(Day2\)的题目和\(Day1\)比起来,真的是难了很多啊. \(T1\):旅行(点此看 ...

  6. CH Round #55 - Streaming #6 (NOIP模拟赛day2)解题报告

    T1九九归一 描述 萌蛋在练习模n意义下的乘法时发现,总有一些数,在自乘若干次以后,会变成1.例如n=7,那么5×5 mod 7=4,4×5 mod 7=6,6×5 mod 7=2,2×5 mod 7 ...

  7. noip2011提高组day1+day2解题报告

    Day1 T1铺地毯https://www.luogu.org/problem/show?pid=1003 [题目分析] 全部读入以后从最后一个往前找,找到一个矩形的范围覆盖了这个点,那这个矩形就是最 ...

  8. TJOI2015 day2解题报告

    TJOI2015终于写完啦~~~ T1:[TJOI2015]旅游 描述:(BZ没题面只能口述了..)一个人在一棵树上走,每次从a->b会进行一次贸易(也就是在这条路径上买入物品然后在后面卖出)然 ...

  9. noip2015提高组day2解题报告

    1.跳石头 题目描述 一年一度的“跳石头”比赛又要开始了! 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之间,有 N 块岩石( ...

随机推荐

  1. Servlet开发笔记(二)

    ServletContext对象 WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用.        ServletConfig对象中维 ...

  2. 详解WTL应用向导

    之前向 VS2019 中添加了 WTL 应用向导,今天来分析下该应用向导安装的相关文件,最终达到拷贝相关文件到 VS2019 的相应目录中即可直接使用 WTL 应用向导的目的. 在 VS2017 之前 ...

  3. 利用eval函数实现简单的计算器

    """ description : use python eval() function implement a simple calculator functions ...

  4. 在oracle表中增加字段,并调整字段的顺序

    增加字段的语句很简单,以用户身份连接oracle服务: alter table tablename add(colname coltype); # 填上表名.字段名.字段类型 修改字段顺序前,查看表中 ...

  5. (二)jdk8学习心得之Lambda表达式

    二.Lambda表达式 1. 格式 (参数1,参数2,…,参数n)->{方法体} 注意: (参数1,参数2,...,参数n)要与方法接口中的参数一致,但是名字可以不一样. 此外,方法类型接口,有 ...

  6. Tomcat热部署--start tomcat后就可自动部署war包

    使用tomcat图形化界面,需要现在配置文件中设置用户名和密码: 在maven中配置Tomcat插件: root目录下的内容可以直接访问: 跳过测试: 查看端口占用:

  7. 特殊计数序列——第二类斯特林(stirling)数

    计算式 \[ S(n,m)=S(n-1,m-1)+mS(n,m) \] \(S(0,0)=1,S(i,0)=0(i>0)\) 组合意义 将\(n\)个不可分辨的小球放入\(m\)个不可分辨的盒子 ...

  8. anacodna/python 安装 tensorflow

    study from : https://www.cnblogs.com/HongjianChen/p/8385547.html 执行1-6 7 安装jupyter 每次使用tensorflow,都要 ...

  9. Java基础 -- 深入理解迭代器

    在Java基础 -- 持有对象(容器)已经详细介绍到,集合(Collection)的种类有很多种,比如ArrayList.LinkedList.HashSet.... 由于集合的内部结构不同,很多时候 ...

  10. CF451E Devu and Flowers

    多重集求组合数,注意到\(n = 20\)所以可以用\(2 ^ n * n\)的容斥来写. 如果没有限制那么答案就是\(C(n + s - 1, n - 1)\).对每一个限制依次考虑,加上有一种选多 ...