牛客练习赛107

挺有难度的比赛。

A
\((n!)!\mod m,n,m\le 1e6\)

容易发现n!>m之后答案为0。

B
仔细看题。

考虑两个序列中的1能不能都放在一号位可以的话就是最优的。

不能的话考虑一个放1号位另一个顺次放2,3,4...n

这样是代价为1容易发现代价恒大于等于1 故这样也是最优的。

C
注意到\(k>\sqrt n\)生成的k进制数就只有两位了

此时考虑整除分块对于\(n/k\)相同的那么首位都一样 末位形成等差数列 贡献除了最后一个也是等差数列的形式可以计算。

对于小于\(\sqrt n\)的直接暴力计算即可。

可谓是将根号分治和整除分块联系在了一起。

题解区有人发现了直接整除分块除了最后一个答案一直都是等差数列,很神奇。

D
考虑先对\(a_1\)进行操作

\(a_1\)中的0肯定不会变成1而\(a_1\)中的1可以变成0.

进一步可以发现序列中二进制位上0,1个数守恒可以进行交换。

将所有的0尽可能都放前面即可。

E
树上随机选择k个点求这k个点的LCA的期望,每个点都有概率。

还好这个\(k,1\le k\le 5\)

考虑枚举LCA=x 容易想到一个容斥就是选择的k个点在x子树内的概率-k个点在x任意儿子子树内的概率。

\(P_x\)表示x子树内概率总和 那么答案为\(\sum x\cdot (P_x^k-P_{t1}^k-P_{t2}^k-...)\)

接下来考虑单点修改x那么就是从x到1的路径上的点的概率都要修改。

改写一下答案形式不然每个点的地方有两个地方需要修改。

改为\(\sum (x-F_x)\cdot P_x^k\)

左边是一个常数,考虑右边在树上的快速修改,利用树剖和线段树。

考虑线段树上区间的修改即把\(P_x^k\)修改为\((P_x-w)^k\)

如果\(k==1\)那么就可以直接修改了如果\(k==2\)考虑到\((p-w)^2=p^2-2pw-w^2\)需要再维护一个一次方和。

值得注意的是这个一次方和也需要再维护更新。注意到变成加法对于系数而言会更方便。

那么每次区间修改复杂度为\(k^2\)

总复杂度为\(mlog^2k^2\).维护高次方和还是很麻烦的一件事。

代码难度较高,于我不成问题。

code
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<queue>
#include<deque>
#include<stack>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000000000ll
#define inf 100000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define putl_(x) printf("%lld ",x);
#define get(x) x=read()
#define putl(x) printf("%lld\n",x)
#define rep(p,n,i) for(int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define pii pair<int,int>
#define mk make_pair
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define sq sqrt
#define l(w) t[w].l
#define r(w) t[w].r
#define L(w) s[w].l
#define R(w) s[w].r
#define yy p<<1|1
#define zz p<<1
#define sum(w) t[w].sum
#define S second
#define mod 1000000007
#define sc(A) scanf("%d",&A)
#define scs(A) scanf("%s",A);
#define put(A) printf("%d\n",A)
#define min(x,y) (x>=y?y:x)
#define max(x,y) (x>=y?x:y)
#define add(x,y) (x+y>=mod?x+y-mod:x+y)
#define sub(x,y) (x-y<0?x-y+mod:x-y)
using namespace std;
const int MAXN=200010;
int n,m,k,len,cnt;
int a[MAXN],f[MAXN],fa[MAXN],sz[MAXN],son[MAXN],top[MAXN],dfn[MAXN],w[MAXN];
int c[6][6];
ll g[MAXN<<2][6];
int tag[MAXN<<2];
int lin[MAXN],ver[MAXN<<1],nex[MAXN<<1];
inline void add1(int x,int y)
{
	ver[++len]=y;
	nex[len]=lin[x];
	lin[x]=len;
}
inline void dfs(int x,int F)
{
	f[x]=a[x];sz[x]=1;fa[x]=F;
	go(x)
	{
		if(tn==F)continue;
		dfs(tn,x);
		f[x]=add(f[x],f[tn]);
		sz[x]+=sz[tn];
		if(sz[tn]>sz[son[x]])son[x]=tn;
	}
}
inline void dp(int x,int F)
{
	dfn[x]=++cnt;w[cnt]=x;
	top[x]=F;
	if(son[x])dp(son[x],F);
	go(x)
	{
		if(tn==fa[x]||tn==son[x])continue;
		dp(tn,tn);
	}
}
inline void build(int p,int l,int r)
{
	if(l==r)
	{
		g[p][0]=sub(w[r],fa[w[r]]);
		rep(1,k,i)g[p][i]=g[p][i-1]*f[w[r]]%mod;
		return;
	}
	int mid=(l+r)>>1;
	build(zz,l,mid);
	build(yy,mid+1,r);
	rep(0,k,i)g[p][i]=add(g[zz][i],g[yy][i]);
}
inline void pushdown(int p)
{
	for(int i=k;i>=1;--i)
	{
		int ans=0,ww=1,ans1=0;
		for(int j=0;j<=i;++j)
		{
			int cnt=g[zz][i-j]*c[i][j]%mod*ww%mod;
			ans=add(ans,cnt);
			cnt=g[yy][i-j]*c[i][j]%mod*ww%mod;
			ans1=add(ans1,cnt);
			ww=(ll)ww*tag[p]%mod;
		}
		g[zz][i]=ans;g[yy][i]=ans1;
	}
	tag[zz]=add(tag[zz],tag[p]);
	tag[yy]=add(tag[yy],tag[p]);
	tag[p]=0;
}
inline void change(int p,int l,int r,int L,int R,int w)
{
	if(L<=l&&R>=r)
	{
		tag[p]=add(tag[p],w);
		for(int i=k;i>=1;--i)
		{
			int ans=0,ww=1;
			for(int j=0;j<=i;++j)
			{
				int cnt=g[p][i-j]*c[i][j]%mod*ww%mod;
				ans=add(ans,cnt);
				ww=(ll)ww*w%mod;
			}
			g[p][i]=ans;
		}
		return;
	}
	int mid=(l+r)>>1;
	if(tag[p])pushdown(p);
	if(L<=mid)change(zz,l,mid,L,R,w);
	if(R>mid)change(yy,mid+1,r,L,R,w);
	rep(1,k,i)g[p][i]=add(g[zz][i],g[yy][i]);
}
inline void change(int x,int w)
{
	while(top[x]!=1)
	{
		change(1,1,n,dfn[top[x]],dfn[x],w);
		x=fa[top[x]];
	}
	change(1,1,n,dfn[1],dfn[x],w);
}
inline int ksm(int b,int p)
{
	int cnt=1;
	while(p)
	{
		if(p&1)cnt=(ll)cnt*b%mod;
		b=(ll)b*b%mod;p=p>>1;
	}
	return cnt;
}
inline void ask()
{
	int cc=1;
	rep(1,k,j)cc=(ll)f[1]*cc%mod;
	cc=g[1][k]*ksm(cc,mod-2)%mod;
	put(cc);
}
int main()
{
	//freopen("1.in","r",stdin);
	sc(n);sc(m);sc(k);
	c[0][0]=1;
	rep(1,k,i)
	{
		c[i][0]=1;
		rep(1,i,j)c[i][j]=add(c[i-1][j],c[i-1][j-1]);
	}
	rep(1,n,i)sc(a[i]);
	rep(2,n,i)
	{
		int x,y;
		sc(x);sc(y);
		add1(x,y);add1(y,x);
	}
	dfs(1,0);
	dp(1,1);
	build(1,1,cnt);
	ask();
	rep(1,m,i)
	{
		int x,w,cc;
		sc(x);sc(w);cc=sub(w,a[x]);
		change(x,cc);
		a[x]=w;f[1]=add(f[1],cc);
		ask();
	}
	return 0;
}
F 会更的!!!

有点崩溃 家里wifi信号挺拉的 手机流量也拉,估计是手机不行了。

努力学习来赚钱吧。

这个题明显可以利用生成函数来做。用EGF来做。

式子很好列,就有一步求和需要手工计算一下。之后只需要多项式乘法与求逆即可。

既然游戏打不了了,不如打代码,当个多项式带师。

有个多项式需要求逆,但是前k项都为0,搞不懂系数怎么办 无奈。

在坚持不懈的重构代码的情况下终于过了。

先是不知道快速幂NTT会被卡 后是多项式Exp自己写的被卡。

前者大概要8s太慢了 后者是没考虑到边界情况导致一直wa.

大概是熟悉了一点了。

code
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<ctime>
#include<cctype>
#include<queue>
#include<deque>
#include<stack>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 1000000000000000ll
#define inf 100000000000000000ll
#define ldb long double
#define pb push_back
#define put_(x) printf("%d ",x);
#define putl_(x) printf("%lld ",x);
#define get(x) x=read()
#define putl(x) printf("%lld\n",x)
#define rep(p,n,i) for(int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define pii pair<int,int>
#define mk make_pair
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define uint unsigned long long
#define ui unsigned
#define sq sqrt
#define l(w) t[w].l
#define r(w) t[w].r
#define L(w) s[w].l
#define R(w) s[w].r
#define yy p<<1|1
#define zz p<<1
#define sum(w) t[w].sum
#define S second
#define mod 998244353
#define sc(A) scanf("%d",&A)
#define scs(A) scanf("%s",A);
#define put(A) printf("%d\n",A)
#define min(x,y) (x>=y?y:x)
#define max(x,y) (x>=y?x:y)
#define add(x,y) (x+y>=mod?x+y-mod:x+y)
#define sub(x,y) (x-y<0?x-y+mod:x-y)
using namespace std;
const int MAXN=600010,G=3;
int n,k,m,lim,IG;
int fac[MAXN],INV[MAXN],inv[MAXN];
int A[MAXN],B[MAXN],C[MAXN],O[MAXN],f[MAXN],g[MAXN],D[MAXN];
int a[MAXN],b[MAXN],c[MAXN],rev[MAXN],tmp1[MAXN],tmp2[MAXN];
inline int ksm(int b,int p)
{
	int cnt=1;
	while(p)
	{
		if(p&1)cnt=(ll)cnt*b%mod;
		p=p>>1;b=(ll)b*b%mod;
	}
	return cnt;
}
inline void NTT(int *a,int op,int lim)
{
	rep(0,lim-1,i)
	{
		rev[i]=rev[i>>1]>>1|((i&1)?lim>>1:0);
		if(i<rev[i])swap(a[i],a[rev[i]]);
	}
	for(int len=2;len<=lim;len=len<<1)
	{
		int mid=len>>1;
		int wn=ksm(op==1?G:IG,(mod-1)/len);
		rep(1,mid-1,j)O[j]=(ll)O[j-1]*wn%mod;
		for(int j=0;j<lim;j+=len)
		{
			rep(0,mid-1,i)
			{
				int x=(ll)a[i+j+mid]*O[i]%mod;
				a[i+j+mid]=sub(a[i+j],x);
				a[i+j]=add(a[i+j],x);
			}
		}
	}
	if(op==-1)
	{
		int w=ksm(lim,mod-2);
		rep(0,lim-1,i)a[i]=(ll)a[i]*w%mod;
	}
}
inline void QD(int *A,int *B,int n)
{
	rep(0,n,i)B[i]=(ll)A[i+1]*(i+1)%mod;B[n]=0;
}
inline void JF(int *A,int *B,int n)
{
	rep(1,n,i)B[i]=(ll)A[i-1]*INV[i]%mod;B[0]=0;
}
inline void sol(int n,int *a,int *b)
{
	if(n==1){b[0]=ksm(a[0],mod-2);return;}
	sol((n+1)>>1,a,b);
	int s=1;
	while(s<=n+n-1-1)s=s<<1;
	rep(0,n-1,i)D[i]=a[i];
	rep(n,s-1,i)D[i]=0;
	NTT(D,1,s);NTT(b,1,s);
	for(int i=0;i<s;++i)b[i]=(2-1ll*D[i]*b[i]%mod+mod)%mod*b[i]%mod;
	NTT(b,-1,s);
	rep(n,s-1,i)b[i]=0;
}
inline void In(int *A,int *B,int n)
{
	int s=1;
	while(s<=n+n)s=s<<1;
	rep(0,s-1,i)tmp1[i]=tmp2[i]=0;
    QD(A,tmp1,n);sol(n+1,A,tmp2);
	NTT(tmp1,1,s);NTT(tmp2,1,s);
	rep(0,s-1,i)tmp1[i]=(ll)tmp1[i]*tmp2[i]%mod;
	NTT(tmp1,-1,s);
	JF(tmp1,B,n);
}
inline void Exp(int *A,int *B,int n)
{
	if(n==1)return B[0]=1,void();
	Exp(A,B,(n+1)>>1);In(B,b,n-1);
	rep(0,n,i)b[i]=sub(A[i],b[i]);
	b[0]=add(b[0],1);
	int s=1;
	while(s<=n+n)s=s<<1;
	NTT(B,1,s);NTT(b,1,s);
	rep(0,s-1,i)B[i]=(ll)B[i]*b[i]%mod;
	NTT(B,-1,s);
	rep(0,s-1,i)
	{
		if(i>n)B[i]=0;
		b[i]=0;
	}
}
int main()
{
	//freopen("1.in","r",stdin);
	sc(n);sc(m);sc(k);
	fac[0]=1;
	rep(1,n+k,i)fac[i]=(ll)fac[i-1]*i%mod;
	inv[n+k]=ksm(fac[n+k],mod-2);
	for(int i=n+k-1;i>=0;--i)inv[i]=(ll)inv[i+1]*(i+1)%mod,INV[i+1]=(ll)inv[i+1]*fac[i]%mod;
	rep(0,n,i)c[i]=inv[i],a[i]=i<=k-1?inv[i]:0;
	O[0]=1;IG=ksm(G,mod-2);
	//rep(0,n,i)cout<<c[i]<<endl;
	In(c,C,n+k);
	//rep(0,n,i)cout<<C[i]<<endl;
	In(a,A,n+k);
	rep(0,n+k,i)C[i]=(ll)C[i]*m%mod,A[i]=(ll)A[i]*m%mod;
	Exp(C,f,n+k+1);
	Exp(A,g,n+k+1);
	//f=c^m g=a^m
	lim=1;while(lim<=n+k+n+k)lim=lim<<1;
	NTT(f,1,lim);NTT(c,1,lim);NTT(g,1,lim);NTT(a,1,lim);
	rep(0,lim-1,i)f[i]=(ll)f[i]*c[i]%mod,tmp1[i]=(ll)g[i]*c[i]%mod,g[i]=(ll)g[i]*a[i]%mod;
	NTT(f,-1,lim);NTT(g,-1,lim);NTT(tmp1,-1,lim);
	rep(n+k+1,lim-1,i)f[i]=g[i]=tmp1[i]=0;
	//f=C^(m+1) g=A^(m+1) tmp1=A^mC%
	rep(0,n+k,i)g[i]=(ll)g[i]*m%mod,tmp1[i]=(ll)tmp1[i]*(m+1)%mod,f[i]=sub(add(f[i],g[i]),tmp1[i]);
	//求B的逆
	rep(0,n-k,i)B[i]=inv[i+k];
	sol(n+1,B,b);
	NTT(b,1,lim);NTT(f,1,lim);
	rep(0,lim-1,i)f[i]=(ll)f[i]*b[i]%mod;
	NTT(f,-1,lim);
	int w=ksm(m,n);w=ksm(w,mod-2);
	put((ll)f[n+k]*fac[n]%mod*w%mod);
	return 0;
}
细节太多了吧这也我也顶不住。
posted @ 2023-01-02 09:49  chdy  阅读(62)  评论(0编辑  收藏  举报