首页 > 其他分享 >luogu P5291 [十二省联考 2019] 希望

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

时间:2023-01-10 21:46:52浏览次数:59  
标签:Le int luogu ll 2019 Sn && 联考 mod

题面传送门

真的很想吐。

题目的意思大概就是在一棵树上选出\(k\)个联通块,使得这\(k\)个联通块有交。

显然联通块的交还是联通块,因此转化为对联通块计数。而联通块个数等于点数减去边数,因此可以分别对点和边计数。

设\(f_{i,j}\)表示\(i\)子树中最深的点小于\(j\)的联通块有多少个,\(g_{i,j}\)表示\(i\)子树外最深为\(j\)的联通块有多少个。则点的答案为\(f_{i,L}\times g_{i,L}\),边的答案为\(f_{i,L-1}\times (g_{i,L}-1)\)。

转移方程大概就是\(f_{i,j}=\prod\limits_{(u,i)\in E,u\not=fa_i}{f_{u,j}+1}\),\(g\)类似。

发现第二维和深度有关,考虑长链剖分。长链剖分优化\(f\)是套路的,即我们要支持单点查/改,整体加,后缀乘。可以全局维护加法和乘法标记,然后后缀乘转化为前缀乘,复杂度是正确的。

优化\(g\)的过程可以看作\(f\)的反过程。容易发现对于\(i\)子树内从父亲拿下来的信息,只有深度在\([L-len_i,L]\)范围内的状态是有用的,因此轻儿子暴力转移的复杂度和长剖类似,是\(O(n)\)的,也要维护像\(f\)类似的东西。

重儿子直接从轻儿子转移复杂度也是正确的。

总共的复杂度是\(O(n\log p)\),瓶颈在逆元上。但是有个问题,如果恰好模\(p\)余\(0\)是没有逆元的。但是这样的概率可以看作在\([0,p-1]\)中选一个数选到\(p-1\)的概率,则直接暴力即可。

然后exgcd的逆元显著快于费马小定理,卡卡常能过。

code:

#include<bits/stdc++.h>
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n))
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=1e6+5,M=2.5e3+5,K=1e5+5,mod=998244353,Mod=mod-1;const int INF=2e9+7;const db eps=1e-5;mt19937 rnd(263082);
int n,m,k,x,y,z,Sn[N],Le[N],B[N],Bh;ll Ans;vector<int> S[N];
ll mpow(ll x,int y=mod-2){ll Ans=1;while(y) y&1&&(Ans=Ans*x%mod),y>>=1,x=x*x%mod;return Ans;}
void EG(ll x,int p,ll &a,ll &b){if(!p){a=1;b=0;return;}EG(p,x%p,a,b);swap(a,b);b-=x/p*a;}
ll GI(ll x){ll y,z;EG(x,mod,y,z);return (y%mod+mod)%mod;}
void Make1(int x,int La){for(int i:S[x]) i^La&&(Make1(i,x),Le[i]+1>Le[x]&&(Le[x]=Le[i]+1,Sn[x]=i));}
void Make2(int x,int La){if(!Sn[x]) return;B[Sn[x]]=B[x]+1;Make2(Sn[x],x);for(int i:S[x]) i^La&&i^Sn[x]&&(B[i]=Bh+1,Bh+=Le[i]+1,Make2(i,x),0);}
struct Node{
	ll k,b,inv;
	Node operator *(const Node &B)const{return (Node){k*B.k%mod,b*B.k%mod,inv*B.inv%mod};}
	Node operator +(const Node &B)const{return (Node){k,(b+B.b)%mod,inv};}
	ll calc(ll x){return (x*k+b)%mod;}
}F[N],Cl=(Node){1,0,1},G[N];
ll f[N],g[N];
vector<pair<int,ll>> SS[N];
void mul(ll &x,ll w,Node p){x=(p.calc(x)*w%mod+mod-p.b)*p.inv%mod;}
void dfs1(int x,int La){
	int i,j;
	if(Sn[x])dfs1(Sn[x],x),F[B[x]]=F[B[x]+1];else F[B[x]]=Cl;
	f[B[x]]=(mod-F[B[x]].b)*F[B[x]].inv%mod;F[B[x]]=F[B[x]]+(Node){0,1,0};
	for(int i:S[x]) if(i^La&&i^Sn[x]){
		dfs1(i,x);for(j=0;j<Le[i];j++) SS[x].PB({B[x]+j+1,f[B[x]+j+1]}),mul(f[B[x]+j+1],F[B[i]].calc(f[B[i]+j])+1,F[B[x]]);
		ll s=(F[B[i]].calc(f[B[i]+Le[i]])+1)%mod,p=GI(s);
	//	if(!s){
	//		for(j=Le[i]+1;j<=Le[x];j++) SS[x].PB({B[x]+j,f[B[x]+j]}),mul(f[B[x]+j],0,F[B[x]]);
	//	}else{
			for(j=0;j<=Le[i];j++) mul(f[B[x]+j],p,F[B[x]]);
			F[B[x]]=F[B[x]]*(Node){s,0,p}; 
	//	}
	}
}
void dfs2(int x,int La){
	int i,j;if(Le[x]>=m) g[B[x]+m]=(mod-G[B[x]].b)*G[B[x]].inv%mod;G[B[x]].b++;
	if(Sn[x]){
		for(int i:S[x]) if(i^La&&i^Sn[x]){
			//if(x==9&&i==8) cerr<<"asdf "<<G[B[x]].calc(g[B[x]+1])<<' '<<F[B[x]].calc(f[B[x]+min(Le[x],m-1)])<<' '<<mpow(F[B[i]].calc(f[B[i]+min(Le[i],m-2)])+1)<<'\n';
			for(j=0;j<=Le[i];j++) if(m-j-1>0){
				ll s=(F[B[i]].calc(f[B[i]+min(Le[i],m-j-2)])+1)%mod;
				if(s) g[B[i]+j]=G[B[x]].calc(g[B[x]+j+1])*F[B[x]].calc(f[B[x]+min(Le[x],m-j-1)])%mod*GI(s)%mod;
			}
			else if(m-j-1==0) g[B[i]+j]=G[B[x]].calc(g[B[x]+j+1])*F[B[x]].calc(f[B[x]+min(Le[x],m-j-1)])%mod;
			else if(m-j-1<0) g[B[i]+j]=0;
		}
		G[B[x]+1]=G[B[x]]+G[B[x]+1];
		for(int i:S[x]) if(i^La&&i^Sn[x]){
			for(j=0;j<=Le[i];j++) if(j+2>=m-Le[Sn[x]]&&j+2<=m) mul(g[B[x]+1+m-(j+2)],F[B[i]].calc(f[B[i]+j])+1,G[B[x]+1]);
			if(Le[i]+2<m){
				ll s=(F[B[i]].calc(f[B[i]+Le[i]])+1)%mod,p=GI(s);
				//if(!s){
				//	for(j=Le[i]+1;j<=m-2;j++) if(j+2>=m-Le[Sn[x]]) mul(g[B[x]+1+m-(j+2)],0,G[B[x]+1]);
				//} else{
					for(j=-2;j<=Le[i];j++) if(j+2>=m-Le[Sn[x]]&&j+2<=m) mul(g[B[x]+1+m-(j+2)],p,G[B[x]+1]);
					G[B[x]+1]=G[B[x]+1]*(Node){s,0,p};	
				//}
			}
		}
		/*for(int i:S[x]) if(i^La){
			for(j=1;j<=m;j++) g[i][j]=g[x][j-1];
			for(j=2;j<=m;j++) g[i][j]=g[i][j]*F[B[x]].calc(f[B[x]+min(Le[x],j-1)])%mod*mpow(F[B[i]].calc(f[B[i]+min(Le[i],j-2)])+1)%mod;
		}*/
	}
	reverse(S[x].begin(),S[x].end());
	if(La&&m)Ans-=mpow(F[B[x]].calc(f[B[x]+min(m-1,Le[x])])*(G[B[x]].calc(g[B[x]])-1+mod)%mod,k);Ans+=mpow(F[B[x]].calc(f[B[x]+min(m,Le[x])])*G[B[x]].calc(g[B[x]])%mod,k);
	printf("%d %lld %lld\n",x,F[B[x]].calc(f[B[x]+min(m,Le[x])]),G[B[x]].calc(g[B[x]]));
	reverse(SS[x].begin(),SS[x].end());for(auto i:SS[x]) f[i.first]=i.second;
	if(Sn[x]){
		for(int i:S[x]) if(i^La&&i^Sn[x]){
			//if(x==9&&i==8) cerr<<"asdf "<<G[B[x]].calc(g[B[x]+1])<<' '<<F[B[x]].calc(f[B[x]+min(Le[x],m-1)])<<' '<<mpow(F[B[i]].calc(f[B[i]+min(Le[i],m-2)])+1)<<'\n';
			for(j=0;j<=Le[i];j++) if(m-j-1>0){
				ll s=(F[B[i]].calc(f[B[i]+min(Le[i],m-j-2)])+1)%mod;
				if(!s){
					g[B[i]+j]=G[B[x]].calc(g[B[x]+j+1]);
					for(int p:S[x]) if(i^p&&p^La) g[B[i]+j]=g[B[i]+j]*(F[B[p]].calc(f[B[p]+min(m-j-2,Le[p])])+1)%mod;
				}
			}
		}
	}
	for(int i:S[x]) i^La&&(i^Sn[x]&&(G[B[i]]=Cl,0),dfs2(i,x),0);
}
int main(){
	freopen("hope.in","r",stdin);freopen("hope.out","w",stdout); 
	int i,j;scanf("%d%d%d",&n,&m,&k);for(i=1;i<n;i++) scanf("%d%d",&x,&y),S[x].PB(y),S[y].PB(x);
	Make1(1,0);B[1]=1;Bh=Le[1]+1;Make2(1,0);
	dfs1(1,0);
	G[1]=Cl;dfs2(1,0);
	printf("%lld\n",(Ans%mod+mod)%mod); 
}

标签:Le,int,luogu,ll,2019,Sn,&&,联考,mod
From: https://www.cnblogs.com/275307894a/p/17041433.html

相关文章

  • 十二省联考 2019 题解
    Day1B字符串问题朴素的想法是,建一张\(n_a+n_b\)个点的有向图\(G\)。对于一个支配关系\((x,y)\),从\(x\)向\(y+n_a\)连边。此外,枚举\(1\lei\len_b\),对于每个......
  • [luogu]P2123 皇后游戏
    题目传送门分析和国王游戏一样的思路直接考虑邻项交换观察易知排在后面的大臣获得的奖赏一定更多假设前\(i-1\)位左手上的数和为\(a\),第\(i-1\)位获得奖赏为\(......
  • windows10下QT5.9.9安装和在VS2019中环境部署(保姆级教程)
    https://www.cnblogs.com/unicornsir/articles/16825578.html1.下载QT5.9.92.安装QT,最好提前注册号一个QT账号(不提前注册也可以,看后面操作)3.在VS2019中部署QT5.9.94.......
  • luogu P1971 [NOI2011] 兔兔与蛋蛋游戏
    题面传送门没想到二分图博弈这么早就考了?首先我们发现,如果将和起点行列之和奇偶性一样的点设为黑色,其余设为白色,那么每次空格只会在异色边之间走,而不会在同色边之间走。......
  • re | [RCTF2019]asm
    re|[RCTF2019]asm简单file一下:推测是risc-v64位,去网上找逆向脚本:这个反汇编器是可以用的:https://github.com/riscv/riscv-gnu-toolchain或者用下面这个idaproc可以......
  • Luogu P4592 [TJOI2018]异或 做题记录
    随机跳的。树上维护序列,显然树剖。维护异或,显然01trie。01trie维护区间异或,显然可持久化一下。看到时限很大,显然可以双log。于是跑一边树剖,再根据id暴力建一个可......
  • SQL Server 2019 普通时间转换成UNIX时间戳
    SQLServer2019普通时间转换成UNIX时间戳一、前言由于在查询时,经常使用到DATETIME2类型数据date_time列,查询效率比较低,用时也很长。如果能转换成BIGINT类型的UNI......
  • C# winform使用InstallShield2019打包
    C#winform使用InstallShield2019打包莫凭栏_于 2019-12-0420:08:59 发布1624收藏3分类专栏:软件文章标签:C#Installshield2019winform......
  • luogu P5037 抓捕
    ##题意有$n$个点的图,任意一点$x$到可去另外一点$y$必须互质,即$\gcd(x,y)=1$。图无边权,但是拥有点权。求到终点$en$的最短距离。---##思路此题需使用Dijks......
  • [2019强网杯]随便注
    [2019强网杯]随便注考点:1、堆叠注入 2、sql预处理语句之前做过的一道题,再次遇到发现还是有很多需要学习的地方,也没有记录过堆叠注入的题,所以就想着记一下这道题的一些知......