省選模擬賽Round4 Day2 墨水大師 分岔路口 有趣的字符串題

最後一次模擬賽了

不知爲什麼感覺有點失落

image

 

題解

考場上已經想到正解的一半了,建圓方樹DP

後面的步驟稍微思考了一下,發現要分治NTT+多項式多點求值(當場自閉)

於是就只有50分

正解:

考慮對每一個環計算答案,最後就是所有的環的答案乘起來

而每一個環的答案只與環長有關,容斥一下,發現答案是一個等比數列,直接求和做到O(logn)(快速冪複雜度)

一棵仙人掌的環長最多隻有O(sqrt(n))種

所以總複雜度爲O(Q*sqrt(n)*logn)

究級卡常題

代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
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<int> 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<<i)<=sz[hcnt];i++)pw[i]=1ll*pw[i-1]*pw[i-1]%mod;
		
		for(i=1;i<=hcnt;i++){
			pp=1ll*pp*kksm(sz[i]-sz[i-1])%mod;
			int tmp;
			if(!(sz[i]&1))tmp=1ll*(pp-1)*ni%mod;
			else tmp=1ll*(1+mod-pp)*ni%mod;
			tmp+=((sz[i]&1)?mod-1:1);
			if(tmp>=mod)tmp-=mod;
			ans=1ll*ans*ksm(tmp,con[i])%mod;
		}
		ans=1ll*ans*C%mod;
		printf("%d\n",ans);
	}
}

 

 

 

 

image

 

 

題解

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

顯然,我們一定是先隨機跳,跳到一定的範圍之後直接走最優

我們可以二分這個範圍的大小

然後就會發現一個概率DP中常見性質:所有在這個範圍外的點的期望步數是相等的

設在這個範圍外的期望是x

那麼有方程:

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

sumdis表示在mid範圍內的點到終點的距離之和

cnt表示在mid範圍內的點的個數

稍微移一下項得

x=(n+sumdis)/cnt

如果這個x大於了我們的mid,就需要增大mid,否則就減小

sumdis和cnt可以通過點分樹維護

代碼:(有點噁心)

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
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<LL> 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<LL,LL> 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]<dep[y])swap(x,y);
	int d=dep[x]-dep[y];
	for(int i=LOG-1;i>=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<n;i++){u=gi();v=gi();adde(u,v);}
	DFS::work();dfs(1);
	for(j=1;j<LOG;j++)for(i=1;i<=n;i++)
		f[j][i]=f[j-1][f[j-1][i]];
	while(Q--){
		u=gi();v=gi();
		l=0;r=n;
		while(l<r){
			mid=(l+r)>>1;
			pair<LL,LL> tmp=DFS::query(v,mid);
			if(1.0*(n+tmp.second)/tmp.first<mid)r=mid;
			else l=mid+1;
		}
		pair<LL,LL> 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)]));
	}
}

 

 

image

 

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

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章