省选模拟赛Round4 Day2 墨水大师 分岔路口 有趣的字符串题

最后一次模拟赛了

不知为什么感觉有点失落

省选模拟赛Round4 Day2 墨水大师 分岔路口 有趣的字符串题_第1张图片

 

题解

考场上已经想到正解的一半了,建圆方树DP

后面的步骤稍微思考了一下,发现要分治NTT+多项式多点求值(当场自闭)

于是就只有50分

正解:

考虑对每一个环计算答案,最后就是所有的环的答案乘起来

而每一个环的答案只与环长有关,容斥一下,发现答案是一个等比数列,直接求和做到O(logn)(快速幂复杂度)

一棵仙人掌的环长最多只有O(sqrt(n))种

所以总复杂度为O(Q*sqrt(n)*logn)

究级卡常题

代码:

#include
#include
#include
#include
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 200005
vector G[N],gid[N];
int fir[N],to[N],nxt[N],cnt;
void adde(int a,int b)
{
	to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;
}
int dfn[N],low[N],stk[N],sz[N],top,dc,tot;
void dfs(int u,int pp)
{
	dfn[u]=low[u]=++dc;
	stk[top++]=u;
	for(int v,i=0;i<(int)G[u].size();i++){
		if(gid[u][i]!=pp){
			v=G[u][i];
			if(!dfn[v]){
				dfs(v,gid[u][i]);
				low[u]=min(low[u],low[v]);
				if(low[v]>=dfn[u]){
					adde(u,++tot);sz[tot]=1;
					while(top>0){
						adde(tot,stk[--top]);
						sz[tot]++;
						if(stk[top]==v)break;
					}
				}
			}
			else low[u]=min(low[u],dfn[v]);
		}
	}
}
const int mod=998244353;
int C,n,m,Q,con[N],pw[35],lg[N];
inline int ksm(int x,int y)
{
	if(y==1)return x;
	if(y==2)return 1ll*x*x%mod;
	if(y==3)return 1ll*x*x%mod*x%mod;
	if(y==4)return 1ll*x*x%mod*x%mod*x%mod;
	int ret=1;
	while(y){
		if(y&1)ret=1ll*ret*x%mod;
		y>>=1;x=1ll*x*x%mod;
	}
	return ret;
}
inline int kksm(int y)
{
	int ret=1;
	for(;y;y-=(y&-y))
		ret=1ll*ret*pw[lg[y&-y]]%mod;
	return ret;
}
int main()
{
	freopen("inkmaster.in","r",stdin);
	freopen("inkmaster.out","w",stdout);
	int i,u,v;
	n=gi();m=gi();Q=gi();
	lg[0]=-1;for(i=1;i<=n;i<<=1)lg[i]=lg[i>>1]+1;
	for(i=1;i<=m;i++){
		u=gi();v=gi();
		G[u].push_back(v);gid[u].push_back(i);
		G[v].push_back(u);gid[v].push_back(i);
	}
	tot=n;
	for(i=1;i<=n;i++)
		if(!dfn[i])dfs(i,0);
	tot-=n;
	for(i=1;i<=tot;i++)sz[i]=sz[i+n];
	sort(sz+1,sz+tot+1);
	int hcnt=0;
	for(i=1;i<=tot;i++){
		if(sz[i]!=sz[i-1]){
			sz[++hcnt]=sz[i];
			con[hcnt]=0;
		}
		con[hcnt]++;
	}
	int ans;
	while(Q--){
		C=gi();
		ans=1;
		int ni=ksm(C,mod-2),pp=1;
		pw[0]=(1+mod-C)%mod;
		for(i=1;(1<=mod)tmp-=mod;
			ans=1ll*ans*ksm(tmp,con[i])%mod;
		}
		ans=1ll*ans*C%mod;
		printf("%d\n",ans);
	}
}

 

 

 

 

省选模拟赛Round4 Day2 墨水大师 分岔路口 有趣的字符串题_第2张图片

 

 

题解

白送了70分没拿到啊啊啊。。。

显然,我们一定是先随机跳,跳到一定的范围之后直接走最优

我们可以二分这个范围的大小

然后就会发现一个概率DP中常见性质:所有在这个范围外的点的期望步数是相等的

设在这个范围外的期望是x

那么有方程:

x=1+(sumdis+(n-cnt)*x)/n

sumdis表示在mid范围内的点到终点的距离之和

cnt表示在mid范围内的点的个数

稍微移一下项得

x=(n+sumdis)/cnt

如果这个x大于了我们的mid,就需要增大mid,否则就减小

sumdis和cnt可以通过点分树维护

代码:(有点恶心)

#include
#include
#include
#include
#include
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 100005
#define LOG 19
#define LL long long
const int INF=0x3f3f3f3f;
int n,Q;
int fir[N],to[2*N],nxt[2*N],cnt;
void adde(int a,int b)
{
	to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;
	to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;
}
namespace DFS{
	vector T1[N],T2[N],sum1[N],sum2[N];
	int dfa[N],dep[N];
	int nrt,all,tmpsiz[N];bool vis[N];
	void findrt(int u,int ff){
		int mx=0;tmpsiz[u]=1;
		for(int v,p=fir[u];p;p=nxt[p]){
			if((v=to[p])!=ff&&!vis[v]){
				findrt(v,u);
				tmpsiz[u]+=tmpsiz[v];
				mx=max(mx,tmpsiz[v]);
			}
		}
		mx=max(mx,all-tmpsiz[u]);
		if(2*mx<=all)nrt=u;
	}
	int getrt(int u,int sz){
		all=sz;nrt=-INF;
		findrt(u,0);return nrt;
	}
	int mx1,mx2,tmp[N],tcnt,dis[N][LOG+2];
	void pre(int u,int d,int ff){
		tmp[++tcnt]=u;
		mx1=max(mx1,dis[u][d]);
		mx2=max(mx2,dis[u][d-1]);
		tmpsiz[u]=1;
		for(int v,p=fir[u];p;p=nxt[p]){
			if(!vis[v=to[p]]&&v!=ff){
				dis[v][d]=dis[u][d]+1;
				pre(v,d,u);
				tmpsiz[u]+=tmpsiz[v];
			}
		}
	}
	void DFZ(int u,int d){
		dep[u]=d;vis[u]=1;
		tcnt=mx1=mx2=0;pre(u,d,0);
		T1[u].resize(mx1+1);sum1[u].resize(mx1+1);
		T2[u].resize(mx2+1);sum2[u].resize(mx2+1);
		for(int i=1;i<=tcnt;i++){
			int x=tmp[i];
			T1[u][dis[x][d]]++;
			T2[u][dis[x][d-1]]++;
			sum1[u][dis[x][d]]+=dis[x][d];
			sum2[u][dis[x][d-1]]+=dis[x][d-1];
		}
		for(int i=1;i<=mx1;i++)T1[u][i]+=T1[u][i-1],sum1[u][i]+=sum1[u][i-1];
		for(int i=1;i<=mx2;i++)T2[u][i]+=T2[u][i-1],sum2[u][i]+=sum2[u][i-1];
		for(int v,p=fir[u];p;p=nxt[p])
			if(!vis[v=to[p]]){
				dfa[v=getrt(v,tmpsiz[v])]=u;
				DFZ(v,d+1);
			}
	}
	void work(){DFZ(getrt(1,n),1);}
	pair query(int u,int k){
		if(k<0)return make_pair(0,0);
		LL ret=0,su=0;
		LL c1=0,c2=0,s1=0,s2=0;
		for(int t=u;t;t=dfa[t]){
			if(k-dis[u][dep[t]]>=0){
				c1=T1[t][min((int)T1[t].size()-1,k-dis[u][dep[t]])];
				s1=sum1[t][min((int)sum1[t].size()-1,k-dis[u][dep[t]])];
			}
			else c1=s1=0;
			ret+=c1-c2;
			su+=(s1-s2)+(c1-c2)*dis[u][dep[t]];
			if(dfa[t]&&k-dis[u][dep[t]-1]>=0){
				c2=T2[t][min((int)T2[t].size()-1,k-dis[u][dep[t]-1])];
				s2=sum2[t][min((int)sum2[t].size()-1,k-dis[u][dep[t]-1])];
			}
			else c2=s2=0;
		}
		return make_pair(ret,su);
	}
}//----DFS----
int f[LOG][N],dep[N];
void dfs(int u)
{
	dep[u]=dep[f[0][u]]+1;
	for(int v,p=fir[u];p;p=nxt[p])
		if((v=to[p])!=f[0][u])
			f[0][v]=u,dfs(v);
}
int LCA(int x,int y)
{
	if(dep[x]=0;i--)if((d>>i)&1)x=f[i][x];
	if(x==y)return x;
	for(int i=LOG-1;i>=0;i--)
		if(f[i][x]!=f[i][y])
			x=f[i][x],y=f[i][y];
	return f[0][x];
}
int main()
{
	freopen("branching.in","r",stdin);
	freopen("branching.out","w",stdout);
	int i,j,u,v,l,r,mid;
	n=gi();Q=gi();
	for(i=1;i>1;
			pair tmp=DFS::query(v,mid);
			if(1.0*(n+tmp.second)/tmp.first tmp=DFS::query(v,l-1);
		double g=1.0*(n+tmp.second)/tmp.first;
		printf("%.8f\n",min(g,1.0*dep[u]+dep[v]-2*dep[LCA(u,v)]));
	}
}

 

 

省选模拟赛Round4 Day2 墨水大师 分岔路口 有趣的字符串题_第3张图片

 

题解:https://blog.csdn.net/qq_35950004/article/details/106836626

 

 

 

 

你可能感兴趣的:(总结)