ytq鸽鸽出的题真是毒瘤

原题传送门

题目大意:

有一棵有\(n\)个点的树,求有多少方案选\(k\)个联通块使得存在一个中心点\(p\),所有\(k\)个联通块中所有点到\(p\)的距离都\(\leq L\)

我们先从部分分考虑:

算法1

\(2^{nk}\)枚举联通快判断是否可行

期望得分:8pts

代码就不给了

引理1

对于任意一个联通块,可能成为它的中心点的点组成的集合也是一个联通块。正确性显然

  • 推论

这里作为\(k\)个联通块中心点的点组成的集合是一个联通块

算法2

枚举推论中中心点组成的集合,判断其他是否满足

期望得分:16pts

代码也不给了

引理2

注意到树上联通块中,点集为\(S\),边集为\(E\),有\(|S|-|E|=1\)。正确性显然

这样我们就珂以对每个点、边单独考虑,通过容斥算出答案。设\(f(x)\)表示\(x\)控制的联通块个数,\(g(e)\)表示\(e\)两端点都控制的联通块个数,易知答案为

\[\sum_{v \in V}f(v)^k-\sum_{e \in E}g(e)^k
\]

算法3

我们考虑dp,设\(f_{i,j}\)表示\(i\)点子树中距离\(i\)不超过\(j\)且包含\(i\)的个数,\(g_{i,j}\)表示\(i\)点子树外距离\(i\)不超过\(j\)且包含\(i\)的个数,转移如下:

\[f_{i,j}=\prod_{v \in son(i)}(f_{v,j-1}+1)
\]

\[g_{i,j}=g_{fa_i,j-1}\prod_{v \in son(fa_i),v \neq i}(f_{v,j-2}+1)+1
\]

对于每个点\(i\),对答案的贡献为:

\[(f_{i,L}·g_{i,L})^k
\]

对于每条边\(e\)(设\(v\)为深度更深的点),对答案的贡献为:

\[-(f_{v,L-1}·(g_{v,L}-1))^k
\]

时间复杂度:\(O(nL)\)

期望得分:36pts

算法4:

对于\(L=n\)的测试点,第二维的限制没用了,去掉即可

时间复杂度:\(O(n)\)

期望得分:结合算法3可得48pts

算法5:

对于链的情况,珂以手推一下dp的贡献,发现就是距离,算一下即可

时间复杂度:\(O(n)\)

期望得分:结合算法4可得52pts

这是暴力52pts的做法,代码如下,subtask1是算法3,subtask2是算法4,subtask3是算法5

#include <bits/stdc++.h>
#define mod 998244353
#define N 100005
#define getchar nc
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
inline int power(register int a,register int b)
{
int res=1;
while(b)
{
if(b&1)
res=1ll*res*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return res;
}
struct egde{
int to,next;
}e[N<<2];
int head[N<<1],cnt=0;
inline void add(register int u,register int v)
{
e[++cnt]=(egde){v,head[u]};
head[u]=cnt;
}
int n,m,k,ans;
namespace subtask1{
vector<int> f[N],g[N];
inline void dfs1(register int x,register int fa)
{
for(register int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa)
continue;
dfs1(v,x);
for(register int j=1;j<=m;++j)
f[x][j]=1ll*f[x][j]*(f[v][j-1]+1)%mod;
}
}
inline void dfs2(register int x,register int fa)
{
static int son[N],pre[N],suf[N];
int cnt=0;
for(register int i=head[x];i;i=e[i].next)
if(e[i].to!=fa)
son[++cnt]=e[i].to;
for(register int i=pre[0]=suf[cnt+1]=1;i<=m;++i)
{
if(i>=2)
{
for(register int j=1;j<=cnt;++j)
pre[j]=1ll*pre[j-1]*(f[son[j]][i-2]+1)%mod;
for(register int j=cnt;j>=1;--j)
suf[j]=1ll*suf[j+1]*(f[son[j]][i-2]+1)%mod;
}
else
{
for(register int j=1;j<=cnt;++j)
pre[j]=suf[j]=1;
}
for(register int j=1;j<=cnt;++j)
g[son[j]][i]=(1ll*g[x][i-1]*pre[j-1]%mod*suf[j+1]+1)%mod;
}
for(register int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa)
continue;
ans=(ans+power(1ll*(g[v][m]-1)*f[v][m-1]%mod,k))%mod;
dfs2(v,x);
}
}
inline void solve()
{
for(register int i=1;i<=n;++i)
f[i].resize(m+1,1),g[i].resize(m+1,1);
dfs1(1,0);
dfs2(1,0);
ans=mod-ans;
for(register int i=1;i<=n;++i)
ans=(0ll+ans+power(1ll*f[i][m]*g[i][m]%mod,k))%mod;
write(ans);
}
}
namespace subtask2{
int a[200005],b[200005];
inline void dfs1(register int x,register int fa)
{
for(register int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa)
continue;
dfs1(v,x);
a[x]=1ll*a[x]*(a[v]+1)%mod;
}
}
inline void dfs2(register int x,register int fa)
{
static int son[200005],pre[200005],suf[200005];
int cnt=0;
for(register int i=head[x];i;i=e[i].next)
if(e[i].to!=fa)
son[++cnt]=e[i].to;
pre[0]=suf[cnt+1]=1;
for(register int j=1;j<=cnt;++j)
pre[j]=1ll*pre[j-1]*(a[son[j]]+1)%mod;
for(register int j=cnt;j>=1;--j)
suf[j]=1ll*suf[j+1]*(a[son[j]]+1)%mod;
for(register int j=1;j<=cnt;++j)
b[son[j]]=(1ll*b[x]*pre[j-1]%mod*suf[j+1]+1)%mod;
for(register int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa)
continue;
ans=(ans+power(1ll*(b[v]-1)*a[v]%mod,k))%mod;
dfs2(v,x);
}
}
inline void solve()
{
for(register int i=0;i<=n;++i)
a[i]=b[i]=1;
dfs1(1,0);
dfs2(1,0);
ans=mod-ans;
for(register int i=1;i<=n;++i)
ans=(ans+power(1ll*a[i]*b[i]%mod,k))%mod;
write(ans);
}
}
namespace subtask3{
inline void solve()
{
for(register int i=1;i<=n;++i)
{
int l=max(1,i-m),r=min(n,i+m);
ans=(ans+power(1ll*(i-l+1)*(r-i+1)%mod,k))%mod;
}
for(register int i=2;i<=n;++i)
{
int l=max(1,i-m),r=min(n,i+m-1);
ans=(ans+mod-power(1ll*(i-l+1-1)*(r-i+1)%mod,k))%mod;
}
write(ans);
}
}
int main()
{
n=read(),m=read(),k=read();
if(n<=200000)
{
for(register int i=1;i<n;++i)
{
int u=read(),v=read();
add(u,v),add(v,u);
}
}
if(m==n&&n<=200000)
subtask2::solve();
else if(n<=100000)
subtask1::solve();
else
subtask3::solve();
return 0;
}

算法6

发现\(f,g\)的转移珂以用长链剖分优化,套上一个可持久化数据结构,需要资瓷区间加、区间乘

时间复杂度:\(O(n\log n)\)

期望得分:结合算法5可得84pts

算法7

发现是全局加,后缀乘,这样可以像SDOI2019Day1T1 快速查询

珂以用数组线性维护,为了去掉求逆元的\(log\),我们珂以用类似于求阶乘逆元的方法\(O(n)\)预处理要用的逆元

至此,我们得到了一个\(O(n)\)的做法

期望得分:100pts

#include <bits/stdc++.h>
#define mod 998244353
#define N 1000005
#define getchar nc
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
inline int power(register int a,register int b)
{
int res=1;
while(b)
{
if(b&1)
res=1ll*res*a%mod;
a=1ll*a*a%mod;
b>>=1;
}
return res;
}
struct edge{
int to,next;
}e[N<<1];
int head[N],cnt=0;
inline void add(register int u,register int v)
{
e[++cnt]=(edge){v,head[u]};
head[u]=cnt;
}
int n,m,k;
int dp[N],son[N],len[N],val[N],idx[N],tot,inv[N];
int arr[N<<3],*pos=arr,*f[N<<1],*g[N],ans[2][N],Ans;
inline void dfs1(register int x,register int fa)
{
dp[x]=1;
for(register int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa)
continue;
dfs1(v,x);
son[x]=len[v]>len[son[x]]?v:son[x];
dp[x]=1ll*dp[x]*dp[v]%mod;
}
if(++dp[x]<mod)
val[idx[x]=++tot]=dp[x];
len[x]=len[son[x]]+1;
}
inline void init_inv()
{
static int pre[N];
for(register int i=pre[0]=1;i<=tot;++i)
pre[i]=1ll*pre[i-1]*val[i]%mod;
int pre_inv=power(pre[tot],mod-2);
for(register int i=tot;i;--i)
inv[i]=1ll*pre[i-1]*pre_inv%mod,pre_inv=1ll*pre_inv*val[i]%mod;
}
struct node{
int a,b,inv,pos,num;
};
namespace F{
node tag[N<<1];
vector<pair<node,vector<pair<int,int> > > >backup[N];
inline int get(register int u,register int i)
{
int res=i<tag[u].pos?f[u][i]:tag[u].num;
return (1ll*res*tag[u].a+tag[u].b)%mod;
}
inline void put(register int u,register int i,register int v)
{
f[u][i]=1ll*(v+mod-tag[u].b)*tag[u].inv%mod;
}
inline void merge(register int u,register int v,register int l)
{
node tmp=tag[u];
vector<pair<int,int> >vec;
for(register int i=1;i<=l;++i)
{
vec.push_back(make_pair(i,f[u][i]));
int val=get(v,i-1);
if(i==tag[u].pos)
f[u][tag[u].pos++]=tag[u].num;
put(u,i,1ll*get(u,i)*val%mod);
}
if(l<m)
{
int val=get(v,l);
if(!val)
tag[u].pos=l+1,tag[u].num=mod-1ll*tag[u].b*tag[u].inv%mod;
else
{
int t=inv[idx[v]];
vec.push_back(make_pair(0,f[u][0]));
for(register int i=0;i<=l;++i)
put(u,i,1ll*get(u,i)*t%mod);
tag[u].a=1ll*tag[u].a*val%mod;
tag[u].b=1ll*tag[u].b*val%mod;
tag[u].inv=1ll*tag[u].inv*t%mod;
}
}
if(u<=n)
backup[u].push_back(make_pair(tmp,vec));
}
inline void dfs2(register int x,register int fa)
{
if(son[x])
f[son[x]]=f[x]+1,dfs2(son[x],x),tag[x]=tag[son[x]];
else
tag[x]=(node){1,1,1,n,0};
put(x,0,1);
for(register int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa||v==son[x])
continue;
f[v]=pos;
pos+=len[v];
dfs2(v,x);
merge(x,v,min(len[v]-1,m));
}
ans[0][x]=get(x,min(len[x]-1,m-1));
ans[1][x]=get(x,min(len[x]-1,m));
++tag[x].b;
}
inline void rollback(register int u)
{
tag[u]=backup[u].back().first;
for(register int i=0;i<(backup[u].back().second).size();++i)
f[u][(backup[u].back().second)[i].first]=(backup[u].back().second)[i].second;
backup[u].pop_back();
}
}
namespace G{
node tag[N];
inline int get(register int u,register int i)
{
int res=i<tag[u].pos?g[u][i]:tag[u].num;
return (1ll*res*tag[u].a+tag[u].b)%mod;
}
inline void put(register int u,register int i,register int v)
{
g[u][i]=1ll*(v+mod-tag[u].b)*tag[u].inv%mod;
}
inline void dfs3(register int x,register int fa)
{
if(len[x]-m-1>=0)
put(x,len[x]-m-1,1);
Ans=(Ans+power(1ll*ans[1][x]*get(x,len[x]-1)%mod,k))%mod;
if(fa)
Ans=(Ans-power(1ll*ans[0][x]*(get(x,len[x]-1)+mod-1)%mod,k)+mod)%mod;
if(!son[x])
return;
vector<int> ch;
int maxlen=0;
for(register int i=head[x];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa||v==son[x])
continue;
ch.push_back(v);
maxlen=max(maxlen,len[v]);
}
maxlen=min(maxlen,m);
reverse(ch.begin(),ch.end());
f[x+n]=pos;
pos+=maxlen+1;
F::tag[x+n]=(node){1,1,1,n,0};
F::put(x+n,0,1);
for(register int id=0;id<ch.size();++id)
{
int v=ch[id];
F::rollback(x);
g[v]=pos;
pos+=len[v];
for(register int i=max(len[v]-m-1,0);i<len[v];++i)
{
if(m-len[v]+i==-1)
g[v][i]=get(x,len[son[x]]-len[v]+i);
else
g[v][i]=1ll*get(x,len[son[x]]-len[v]+i)*F::get(x,min(len[x]-1,m-len[v]+i))%mod*F::get(x+n,min(maxlen,m-len[v]+i))%mod;
}
tag[v]=(node){1,1,1,n,0};
F::merge(x+n,v,min(len[v]-1,m));
dfs3(v,x);
}
int v=son[x];
g[v]=g[x];
tag[v]=tag[x];
for(register int i=max(len[v]-m,0);i<=len[v]+maxlen-m-1;++i)
{
if(tag[v].pos==i)
g[v][tag[v].pos++]=tag[v].num;
put(v,i,1ll*get(v,i)*F::get(x+n,m-len[v]+i)%mod);
}
if(maxlen<m)
{
int vv=1,tt=1;
for(register int i=0;i<ch.size();++i)
vv=1ll*vv*val[idx[ch[i]]]%mod,tt=1ll*tt*inv[idx[ch[i]]]%mod;
if(!vv)
tag[v].pos=len[v]+maxlen-m,tag[v].num=mod-1ll*tag[v].b*tag[v].inv%mod;
else
{
for(register int i=max(len[v]-m-1,0);i<=len[v]+maxlen-m-1;++i)
put(v,i,1ll*get(v,i)*tt%mod);
tag[v].a=1ll*tag[v].a*vv%mod;
tag[v].b=1ll*tag[v].b*vv%mod;
tag[v].inv=1ll*tag[v].inv*tt%mod;
}
}
++tag[v].b;
dfs3(v,x);
}
}
int main()
{
n=read(),m=read(),k=read();
for(register int i=1;i<n;++i)
{
int u=read(),v=read();
add(u,v),add(v,u);
}
dfs1(1,0);
init_inv();
f[1]=pos;
pos+=len[1];
F::dfs2(1,0);
g[1]=pos;
pos+=len[1];
G::tag[1]=(node){1,1,1,n,0};
G::dfs3(1,0);
write(Ans);
return 0;
}

【题解】Luogu P5291 [十二省联考2019]希望的更多相关文章

  1. luogu P5291 [十二省联考2019]希望

    luogu loj 无论最终结果将人类历史导向何处 \(\quad\)我们选择 \(\quad\quad\)\(\large{希望}\) 诶我跟你讲,这题超修咸的 下面称离连通块内每个点距离不超过\( ...

  2. 【题解】Luogu P5284 [十二省联考2019]字符串问题

    原题传送门 我用sa做的本题 (码量似乎有点大) 先对原串建sa 考虑如何建图: 从大到小枚举长度len 先将height中等于len的两个位置在并查集合并起来,将lst也合并(lst是链表) 再将长 ...

  3. 【题解】Luogu P5283 [十二省联考2019]异或粽子

    原题传送门 看见一段的异或和不难想到要做异或前缀和\(s\) 我们便将问题转化成:给定\(n\)个数,求异或值最靠前的\(k\)对之和 我们珂以建一个可持久化01trie,这样我们就珂以求出每个值\( ...

  4. 【题解】Luogu P5290 [十二省联考2019]春节十二响

    原题传送门 每个点维护一个堆,表示这个点及其子树所需的每段内存的空间 搜索时从下向上做启发式合并堆中信息,最后根节点堆中所有内存空间之和就是答案 #include <bits/stdc++.h& ...

  5. 题解 loj3050 「十二省联考 2019」骗分过样例

    CASE \(1\sim 3\) \(n\)组测试数据,每次输入一个数\(x\),求\(19^x\). 测试点\(1\),\(x=0,1,\dots n-1\),可以直接递推. 测试点\(2\)要开l ...

  6. Luogu P5285 [十二省联考2019]骗分过样例

    Preface ZJOI一轮被麻将劝退的老年选手看到这题就两眼放光,省选也有乱搞题? 然后狂肝了3~4天终于打完了,期间还补了一堆姿势 由于我压缩技术比较菜,所以用的都是非打表算法,所以一共写了5K- ...

  7. Luogu P5290 [十二省联考2019]春节十二响

    这题是最近看到的今年省选题中最良心的一道了吧 看题+想题+写题都可以在0.5h内解决,送分含义明显啊 首先理解了题意后我们很快就能发现两个点如果要被分在一段那么必须在它们的祖先处合并 首先我们考虑下二 ...

  8. Luogu P5284 [十二省联考2019]字符串问题

    好难写的字符串+数据结构问题,写+调了一下午的说 首先理解题意后我们对问题进行转化,对于每个字符串我们用一个点来代表它们,其中\(A\)类串的点权为它们的长度,\(B\)类串的权值为\(0\) 这样我 ...

  9. Luogu P5283 [十二省联考2019]异或粽子

    感觉不是很难的一题,想了0.5h左右(思路歪了,不过想了一个大常数的两只\(\log\)做法233) 然后码+调了1h,除了一个SB的数组开小外基本上也没什么坑点 先讲一个先想到的方法,我们对于这种问 ...

随机推荐

  1. 被严重误会?APS系统没有想象的那么复杂

    APS的出现要从90年代了,但到现在,很多行业内的顾问或用户提到APS都马上想到的是“要求很精确”“难度很大”“脱离实际”“太理想化”“工作量太大”等等,然后把它束之高阁不睬. 在这里,给大家分析一下 ...

  2. 字符串的sizeof长度及strlen长度

    在C/C++中,字符串是以零('\0')结尾的.比如,对于下面的字符串: "hello"  在最后一个字符'd'后面,还有一个我们肉眼看不见的'\0'字符,作为该字符串的结束符.所 ...

  3. JavaScript深入浅出第3课:什么是垃圾回收算法?

    摘要: JS是如何回收内存的? <JavaScript深入浅出>系列: JavaScript深入浅出第1课:箭头函数中的this究竟是什么鬼? JavaScript深入浅出第2课:函数是一 ...

  4. Linux的权限管理操作-Linux从入门到精通第七天(非原创)

    文章大纲 一.权限概述二.权限设置三.属主与属组设置四.扩展五.学习资料下载六.参考文章 一.权限概述 总述:Linux系统一般将文件可存/取访问的身份分为3个类别:owner.group.other ...

  5. HTTP中分块编码(Transfer-Encoding: chunked)

    转自: 妙音天女--分块传输编码~ 参考链接: HTTP MDN--HTTP协议 一.背景: 持续连接的问题:对于非持续连接,浏览器可以通过连接是否关闭来界定请求或响应实体的边界:而对于持续连接,这种 ...

  6. 目标检测论文解读9——R-FCN

    背景 基于ResNet 101的Faster RCNN速度很慢,本文通过提出Position-sensitive score maps(位置敏感分值图)来给模型加速. 方法 首先分析一下,为什么基于R ...

  7. DVWA之命令执行

    一.命令执行漏洞 命令执行漏洞是指可以随意执行系统命令,属于高危漏洞之一,也属与代码执行范围内,好比说一句话木马<?php@eval($_POST['cmd']);?> 二.分类: 1.代 ...

  8. vue-router路由传递参数 + get传值query获取

    [步骤] (1)路由配置 或者 (2)传递参数 或者 (3)接收传递参数 或者 [二]步骤小结 [三]参数形式 (1)上面这种是/100形式传递过去 (2)另外还有?count=100的格式,这便是g ...

  9. 第09节-使用BTStack编写蓝牙程序

    Bluetooth LE Exploer(微软提供的)可以读取BLE蓝牙设备,可以读写它的值.本篇博客将使用BTStack写出一个精简版的Bluetooth LE Exploer. 涉及文件: bts ...

  10. css做的艺术字效果

    Arctext.js 转自  http://tympanus.net/Development/Arctext/