191026考試題解

T1:求一個網格圖從原點出發走n步,每步等概率往上下左右走,最終到達的點和原點之間的歐氏距離的期望
打個表可以發現是n,完了
具體證明可以推式子或者三角函數

#include<bits/stdc++.h>
#define mod 998244353
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second
#define db double
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
inline void file(){freopen("grid.in","r",stdin);freopen("grid.out","w",stdout);}
int main(){
	#ifdef romiqi
	file();
	#endif
	int n=read()%mod;
	cout<<n;
	return 0;
}

T2:兩棵樹,對於第一棵樹的每條邊,求出刪掉它並在第二棵樹上將對應兩個編號連一條邊再從第二棵樹上選一條邊同樣操作一次之後仍然是兩棵樹的方案數

轉化爲dfs序的限制,通過樹上差分把第二棵樹上某條邊記錄到第一棵樹中,滿足一個限制,另一個限制類似掃描線可以樹狀數組做一下

#include<bits/stdc++.h>
#define pii pair<int,int>
#define pb push_back
#define mp make_pair
#define re register
#define ll long long
#define fi first
#define se second
#define db double
#define re register
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=1000005;
int n;
namespace bit{
	int tr[N];
	inline int lb(int x){return x&(-x);}
	inline void add(int x,int v){for(re int i=x;i<=n;i+=lb(i)) tr[i]+=v;}
	inline int ask(int x){int res=0;for(re int i=x;i;i-=lb(i)) res+=tr[i];return res;}
	inline void modify(int l,int r,int v){add(l,v);add(r+1,-v);}
}
using bit::modify;
using bit::ask;
int idx[N],ans[N];
struct LCA{
	int head[N],nxt[N<<1],vis[N<<1],tot,idd[N<<1];
	inline void add(int x,int y,int i=0){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;idd[tot]=i;}
	int siz[N],hson[N],fa[N],dep[N];
	void dfs1(int v,int kd){
		siz[v]=1;
		for(re int i=head[v];i;i=nxt[i]){
			int y=vis[i];
			if(y==fa[v]) continue;
			fa[y]=v;dep[y]=dep[v]+1;
			if(kd==1) idx[y]=idd[i];
			dfs1(y,kd);
			siz[v]+=siz[y];
			if(siz[y]>siz[hson[v]]) hson[v]=y;
		}
	}
	int top[N],dfn[N],id[N],sign;
	LCA(){sign=0;tot=0;}
	void dfs2(int v){
		dfn[v]=++sign;id[sign]=v;
		top[v]=v==hson[fa[v]]?top[fa[v]]:v;
		for(re int i=head[v];i;i=nxt[i])
			if(!top[vis[i]]) dfs2(vis[i]);
	}
	inline int lca(int x,int y){
		while(top[x]!=top[y])	
			dep[top[x]]>dep[top[y]]?x=fa[top[x]]:y=fa[top[y]];
		return dep[x]<dep[y]?x:y;
	}
	inline int D(int u,int v){return ask(dfn[u])+ask(dfn[v])-2*ask(dfn[lca(u,v)]);}
}tr[3];
vector<int>ad[N],del[N];
void dfs5(int v,int f){
	int res=0;
	if(v>1) res=tr[2].D(v,f);
	for(re int i=tr[1].head[v];i;i=tr[1].nxt[i]){
		int y=tr[1].vis[i];
		if(y==f) continue;
		dfs5(y,v);
	}
	for(re int i=0;i<ad[v].size();++i){int x=ad[v][i];modify(tr[2].dfn[x],tr[2].dfn[x]+tr[2].siz[x]-1,1);}
	for(re int i=0;i<del[v].size();++i){int x=del[v][i];modify(tr[2].dfn[x],tr[2].dfn[x]+tr[2].siz[x]-1,-2);}
	if(v>1) ans[idx[v]]=tr[2].D(v,f)-res;
}
struct E{int x,y,lca;}e[N];
inline void file(){freopen("road.in","r",stdin);freopen("road.out","w",stdout);}
int main(){  int size=100<<20;//40M
    //__asm__ ("movl  %0, %%esp\n"::"r"((char*)malloc(size)+size));//調試用這個 
    __asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));//提交用這個 

    //main函數代碼 
	n=read();
	for(re int x,y,i=1;i<n;++i){x=read(),y=read();tr[1].add(x,y,i),tr[1].add(y,x,i);}
	for(re int x,y,i=1;i<n;++i){
		x=read(),y=read();
		tr[2].add(x,y),tr[2].add(y,x);
		e[i].x=x,e[i].y=y;
	}
	tr[1].dfs1(1,1),tr[1].top[1]=1;tr[1].dfs2(1);
	for(re int i=1;i<n;++i) e[i].lca=tr[1].lca(e[i].x,e[i].y);
	tr[2].dfs1(1,0);tr[2].top[1]=1;tr[2].dfs2(1);
	for(re int x,y,lca,i=1;i<n;++i){
		x=e[i].x,y=e[i].y,lca=e[i].lca;
		if(tr[2].dep[x]<tr[2].dep[y]) swap(x,y);
		ad[x].pb(x),ad[y].pb(x),del[lca].pb(x);
	}
	dfs5(1,0);
	for(re int i=1;i<n;++i) cout<<ans[i]<<" ";
exit(0);//必須用exit 
	return 0;
}

T3:給一個DAG,每條邊有互不相同的權值,把一條路徑經過所有邊的權值按順序記錄下來可以得到一個字符集大小爲1e9,長度爲經過邊數量的字符串,多次詢問從某個點出發第k小的可能的字符串的終點或者判斷無解

設siz表示一個點出發最多走多少不同路徑,把一個點出點中siz最大的點拿出來,會形成一棵樹,然後倍增預處理樹上的信息,查詢時,如果走樹邊無法走到,就二分走哪個非樹邊,需要預處理一下siz的前綴和,走一次非樹邊問題規模至少減少一半(類似輕重鏈剖分),那麼一次詢問複雜度就是log^2的

Code:

#include<bits/stdc++.h>
#define pb push_back
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int INF=1e9,N=2e5+5;
int n,m;
int siz[N];
int s[N][32],t[N][32];
int in[N],cnt=0;
vector<int>fa[N],son[N],sum[N];
inline int search(int x,int k){
	if(!k) return x;
	for(int i=31;i;i--) if(t[x][i] && s[x][i]<=k && s[x][i]+siz[t[x][i]]>=k) return search(t[x][i],k-s[x][i]);
	int p=(--lower_bound(sum[x].begin(),sum[x].end(),k))-sum[x].begin();
	return search(son[x][p+1],k-(~p?sum[x][p]:0)-1);
}
queue<int>q;
int main(){
	n=read(),m=read();
	for(int x,y,i=1;i<=m;i++){
		x=read(),y=read();++in[x];
		son[x].pb(y);fa[y].pb(x);
	}
	for(int i=1;i<=n;i++) if(!in[i]) q.push(i);
	while(!q.empty()){
		int x=q.front();q.pop();++cnt;
		for(auto y:son[x]){
			siz[x]+=siz[y]+1;
			siz[x]=min(siz[x],INF);
			sum[x].pb(siz[x]);
		}
		if(son[x].size()){
			int pos=0;
			for(int i=1;i<son[x].size();i++) if(siz[son[x][i]]>siz[son[x][pos]]) pos=i;
			s[x][0]=1;t[x][0]=son[x][pos];
			for(int i=0;i<pos;i++) s[x][0]+=siz[son[x][i]]+1,s[x][0]=min(s[x][0],INF);
			for(int i=1;i<32;i++){
				t[x][i]=t[t[x][i-1]][i-1];
				if(!t[x][i]) break;
				s[x][i]=s[x][i-1]+s[t[x][i-1]][i-1];
				s[x][i]=min(s[x][i],INF);
			}
		}
		for(auto f:fa[x]) if(!(--in[f])) q.push(f);
	}
	int q=read();
	while(q--){
		int x=read(),k=read();
		if(siz[x]<k) puts("-1");
		else cout<<search(x,k)<<"\n";
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章