题目

比赛界面

T1

数据范围明示直接\(O(n^2)\)计算,问题就在如何快速计算。

树上路径统计通常会用到差分方法。这里有两棵树,因此我们可以做“差分套差分”,在 A 树上对 B 的差分信息进行差分。在修改的时候,我们就会在 A 上 4 个位置进行修改,每次修改会涉及 B 上 4 个位置的差分修改,因此总共会涉及 16 个差分信息的修改。

回收标记的时候,我们可以先在 A 树上进行 DFS ,回收好子树内的差分信息后,再进行一次 B 的回收,得到当前节点上 B 的真实信息。

时间是\(O(n^2+q\log_2n)\)。

#include <cmath>
#include <cstdio> typedef long long LL; const int MAXN = 1e4 + 5, MAXLOG = 15; template<typename _T>
void read( _T &x )
{
x = 0;char s = getchar();int f = 1;
while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
x *= f;
} template<typename _T>
void write( _T x )
{
if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
if( 9 < x ){ write( x / 10 ); }
putchar( x % 10 + '0' );
} struct Tree
{
struct edge
{
int to, nxt;
}Graph[MAXN << 1]; int f[MAXN][MAXLOG];
int head[MAXN], dep[MAXN], seq[MAXN];
int n, ID, lg2, cnt; void addEdge( const int from, const int to )
{
Graph[++ cnt].to = to, Graph[cnt].nxt = head[from];
head[from] = cnt;
} void DFS( const int u, const int fa )
{
f[u][0] = fa, seq[++ ID] = u, dep[u] = dep[fa] + 1;
for( int i = head[u], v ; i ; i = Graph[i].nxt )
if( ( v = Graph[i].to ) ^ fa )
DFS( v, u );
} void init()
{
read( n );
for( int i = 1, a, b ; i < n ; i ++ )
read( a ), read( b ), addEdge( a, b ), addEdge( b, a );
DFS( 1, 0 );
lg2 = log2( n );
for( int j = 1 ; j <= lg2 ; j ++ )
for( int i = 1 ; i <= n ; i ++ )
f[i][j] = f[f[i][j - 1]][j - 1];
} void balance( int &u, const int stp ) const
{
for( int i = 0 ; ( 1 << i ) <= stp ; i ++ )
if( stp & ( 1 << i ) )
u = f[u][i];
} int LCA( int u, int v ) const
{
if( dep[u] > dep[v] ) balance( u, dep[u] - dep[v] );
if( dep[v] > dep[u] ) balance( v, dep[v] - dep[u] );
if( u == v ) return u;
for( int i = lg2 ; ~ i ; i -- ) if( f[u][i] ^ f[v][i] ) u = f[u][i], v = f[v][i];
return f[u][0];
} int fa( const int u ) const { return f[u][0]; }
}; Tree A, B; int dif[MAXN][MAXN];
LL ans; void change( int *d, const int u, const int v, const int lca, const int c )
{
d[u] += c, d[v] += c, d[lca] -= c, d[B.fa( lca )] -= c;
} void recovery( const int u, const int fa )
{
for( int i = A.head[u], v ; i ; i = A.Graph[i].nxt )
if( ( v = A.Graph[i].to ) ^ fa )
recovery( v, u );
for( int i = 1 ; i <= B.n ; i ++ ) dif[fa][i] += dif[u][i];
for( int i = B.n ; i ; i -- )
{
int cur = B.seq[i];
ans ^= 1ll * u * cur * dif[u][cur];
dif[u][B.fa( cur )] += dif[u][cur];
}
} int main()
{
int Q, a1, a2, b1, b2, c, lcaa, lcab;
A.init(), B.init(), read( Q );
while( Q -- )
{
read( a1 ), read( a2 ), read( b1 ), read( b2 ), read( c );
lcaa = A.LCA( a1, a2 ), lcab = B.LCA( b1, b2 );
change( dif[a1], b1, b2, lcab, c );
change( dif[a2], b1, b2, lcab, c );
change( dif[lcaa], b1, b2, lcab, -c );
change( dif[A.fa( lcaa )], b1, b2, lcab, -c );
}
recovery( 1, 0 );
write( ans ), putchar( '\n' );
return 0;
}

T2

神奇的 DP 配合优化,放个官方题解吧:

若每种段只出现一次,可以注意到我们每涂完一种颜色,就将整个序列分为两段,所以,我们不妨令\(f_{i,j}\)表示涂完第\(i\)种颜色到第\(j\)种颜色,最多可以涂多少。那么我们有\(dp_{l,r} = max_{l\leq k \leq r}dp_{l,k−1} + dp_{k+1,r} + cost_{i,j}\),注意到该式虽然与四边形不等式稍有区别,但通过一样的不等式分析仍然可以得到\(dp_{i,j} + dp_{i+1,j+1} \geq dp_{i,j+1} + dp_{i + 1, j}\),故上式可以直接用四边形不等式优化。 一个有意思的现象是,上述决策点似乎只会出现在\(l\)或\(r\),但我并没有想出有效的证明方法。


T3

字符串简单题,考虑容斥。总方案很好计算,然后考虑不相交字符串的方案数。枚举分界点,然后计算左边和右边的回文串数量即可。

所以我为什么会想到奇怪的 slink 方法呀......它还不卡我......

所以就贴了 slink 的代码。

#include <cstdio>
#include <cstring> typedef long long LL; const int MAXN = 2e6 + 5;
const int mod = 998244353, inv2 = 499122177; template<typename _T>
void read( _T &x )
{
x = 0;char s = getchar();int f = 1;
while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
x *= f;
} template<typename _T>
void write( _T x )
{
if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
if( 9 < x ){ write( x / 10 ); }
putchar( x % 10 + '0' );
} int BIT[MAXN], g[MAXN];
int ed[MAXN], slink[MAXN], dif[MAXN];
int ch[MAXN][26], len[MAXN], fa[MAXN], dep[MAXN];
int N, tot, lst;
char S[MAXN]; void add( int &x, const int v ) { x = ( x + v >= mod ? x + v - mod : x + v ); }
int sub( const int x, const int v ) { return ( x < v ? x - v + mod : x - v ); }
LL mul( const int x, const LL v ) { LL tmp = x * v; return tmp < mod ? tmp : tmp % mod; } void up( int &x ) { x += x & ( -x ); }
void down( int &x ) { x -= x & ( -x ); }
void update( int x, const int v ) { for( ; x <= N ; up( x ) ) add( BIT[x], v ); }
int getSum( int x ) { int ret = 0; for( ; x ; down( x ) ) add( ret, BIT[x] ); return ret; }
int query( const int l, const int r ) { return sub( getSum( r ), getSum( l - 1 ) ); } void build()
{
int x;
N = strlen( S + 1 );
len[fa[0] = ++ tot] = -1;
for( int i = 1 ; i <= N ; i ++ )
{
x = S[i] - 'a';
while( S[i] ^ S[i - len[lst] - 1] ) lst = fa[lst];
if( ! ch[lst][x] )
{
int cur = ++ tot, p = fa[lst];
while( S[i] ^ S[i - len[p] - 1] ) p = fa[p];
len[cur] = len[lst] + 2, fa[cur] = ch[p][x], ch[lst][x] = cur;
}
ed[i] = lst = ch[lst][x];
}
} int main()
{
int ans = 0;
scanf( "%s", S + 1 ), build();
for( int i = 2 ; i <= tot ; i ++ )
{
dep[i] = dep[fa[i]] + 1, dif[i] = len[i] - len[fa[i]];
if( dif[i] ^ dif[fa[i]] ) slink[i] = fa[i];
else slink[i] = slink[fa[i]];
}
for( int i = 1 ; i <= N ; i ++ )
{
for( int p = ed[i] ; p ; p = slink[p] )
{
g[p] = query( i - len[slink[p]] - dif[p] + 1, i );
if( slink[p] ^ fa[p] )
{
add( g[p], g[fa[p]] );
add( g[p], mul( ( dep[p] - dep[slink[p]] - 1 ), query( i - dif[p], i ) ) );
}
add( ans, g[p] );
}
add( ans, mul( mul( dep[ed[i]], dep[ed[i]] - 1 ), inv2 ) );
update( i, dep[ed[i]] );
}
write( ans ), putchar( '\n' );
return 0;
}

小结

对于简单题和基础的技巧都还不太熟练,要多加运用。

[noi.ac省选模拟赛]第12场题解集合的更多相关文章

  1. [noi.ac省选模拟赛]第10场题解集合

    题目 比赛界面. T1 不难想到,对于一个与\(k\)根棍子连接的轨道,我们可以将它拆分成\(k+1\)个点,表示这条轨道不同的\(k+1\)段. 那么,棍子就成为了点与点之间的边.可以发现,按照棍子 ...

  2. [noi.ac省选模拟赛]第11场题解集合

    题目   比赛界面. T1   比较简单.容易想到是求鱼竿的最大独立集.由于题目的鱼竿可以被分割为二分图,就可以想到最大匹配.   尝试建边之后会发现边的数量不小,但联系题目性质会发现对于一条鱼竿,它 ...

  3. NOI.AC省选模拟赛第一场 T1 (树上高斯消元)

    link 很容易对于每个点列出式子 \(f_{x,y}=(f_{x,y-1}+f_{x,y}+f_{x,y+1}+f_{x+1,y})/4\)(边角转移类似,略) 这个转移是相互依赖的就gg了 不过你 ...

  4. [NOI.AC省选模拟赛3.31] 星辰大海 [半平面交]

    题面 传送门 思路 懒得解释了......也是比较简单的结论 但是自己看到几何就退缩了...... 下周之内写一个计算几何的学习笔记! Code #include<iostream> #i ...

  5. [NOI.AC省选模拟赛3.31] 附耳而至 [平面图+最小割]

    题面 传送门 思路 其实就是很明显的平面图模型. 不咕咕咕的平面图学习笔记 用最左转线求出对偶图的点,以及原图中每个边两侧的点是谁 建立网络流图: 源点连接至每一个对偶图点,权值为这个区域的光明能量 ...

  6. [NOI.AC省选模拟赛3.30] Mas的童年 [二进制乱搞]

    题面 传送门 思路 这题其实蛮好想的......就是我考试的时候zz了,一直没有想到标记过的可以不再标记,总复杂度是$O(n)$ 首先我们求个前缀和,那么$ans_i=max(pre[j]+pre[i ...

  7. [NOI.AC省选模拟赛3.23] 染色 [点分治+BFS序]

    题面 传送门 重要思想 真的是没想到,我很久以来一直以为总会有应用的$BFS$序,最终居然是以这种方式出现在题目中 笔记:$BFS$序可以用来处理限制点对距离的题目(综合点分树使用) 思路 本题中首先 ...

  8. [NOI.AC省选模拟赛3.23] 集合 [数学]

    题面 传送门 一句话题意: 给定$n\leq 1e9,k\leq 1e7,T\leq 1e9$ 设全集$U=\lbrace 1,2,3,...n\rbrace $,求$(min_{x\in S}\lb ...

  9. [noi.ac省选模拟赛20200606]赌怪

    题目   点这里看题目. 分析   先特判掉\(K=2\)的情况.   首先可以考虑到一个简单 DP :   \(f(i)\):前\(i\)张牌的最大贡献.   转移可以\(O(n^2)\)地枚举区间 ...

随机推荐

  1. 百度编辑器ueditor异步载入的操作方法

    http://www.dookay.com/zh-cn/n/928 百度编辑器ueditor异步载入的操作方法 Time:2014-09-30 | View:830 | Source:佚名 返回列表 ...

  2. Kubernetes学习笔记(四):服务

    服务介绍 服务是一种为一组相同功能的pod提供单一不变接入点的资源.当服务存在时,他的IP和端口不会改变.客户端通过IP和端口建立连接,这些连接会被路由到任何一个pod上.如此,客户端不需要知道每个单 ...

  3. 快速上手Alibaba Arthas

    点击返回上层目录 原创声明:作者:Arnold.zhao 博客园地址:https://www.cnblogs.com/zh94 Arthas 本文主要聚焦于快速上手并使用Arthas,所以对于基本的概 ...

  4. redis使用技巧十连胜,学会工作六到飞起

    Redis 在当前的技术社区里是非常热门的.从来自 Antirez 一个小小的个人项目到成为内存数据存储行业的标准,Redis已经走过了很长的一段路. 随之而来的一系列最佳实践,使得大多数人可以正确地 ...

  5. 基于 abp vNext 和 .NET Core 开发博客项目 - 定时任务最佳实战(一)

    上一篇(https://www.cnblogs.com/meowv/p/12966092.html)文章使用AutoMapper来处理对象与对象之间的映射关系,本篇主要围绕定时任务和数据抓取相关的知识 ...

  6. 深度学习入门: CNN与LSTM(RNN)

    1. 理解深度学习与CNN: 台湾李宏毅教授的入门视频<一天搞懂深度学习>:https://www.bilibili.com/video/av16543434/ 其中对CNN算法的矩阵卷积 ...

  7. PHP获取临时文件的目录路径

    PHP获得临时文件的文件目录相对路径,能够 根据tempnam()和sys_get_temp_dir()函数来完成. 下边我们运用简单的代码实例,给大伙儿介绍PHP获得临时文件的文件目录相对路径的方式 ...

  8. ASP.NET Core 依赖注入最佳实践与技巧

    ASP.NET Core 依赖注入最佳实践与技巧 原文地址:https://medium.com/volosoft/asp-net-core-dependency-injection-best-pra ...

  9. Java-接口的本质

    https://mp.weixin.qq.com/s/tEVw0j18rX2hxt-guXQJ-w 大道至简,本质往往是很朴素的. 本质: 类是主体,接口是主体之间交流沟通的规约. 位置:1. 主体站 ...

  10. Rocket - util - PrefixSum

    https://mp.weixin.qq.com/s/G2vLP-ncoJzSOgxGGEJkfA   简单介绍PrefixSum的实现.   ​​   1. 基本介绍   ​​ 把一个序列从前向后逐 ...