SMU Winter 2024 div2 ptlks的周报Week 6(3.18-3.24)

不难想到,要求环的期望,只需求出所有可能的环的长度总和和不相邻点对的组数。而边数确定,则只需求环的总长。对于两个不相邻的点x,y,所形成的环的长度等于两点深度之差加一,\(\vert dp[x]-dp[y]\vert+1\),不妨令x为根节点,则只需求所有节点的深度之和,再减去相邻的点,最后对树进行换根dp,输出答案即可。

另一道树上问题

题意:给一棵n个节点和n-1条边的树,均匀随机地选取两不相邻的点,求出现的环的期望长度。

代码

#include <bits/stdc++.h>
#define int long long 
#define MOD 1000000007
using namespace std;

int f[1000086]={0},n,sum=0;
vector<int>g[1000086],vis(1000086,0),vis1(1000086,0);
vector<int>cnt(1000086,0);

void dfs(int x,int s){
	vis[x]=1;
	cnt[x]=1;
	int y=0;
	for(int i=0;i<g[x].size();i++){
		if(!vis[g[x][i]]){
			dfs(g[x][i],s+1);
			cnt[x]+=cnt[g[x][i]];
			y+=f[g[x][i]];
			vis[g[x][i]]=0;
		}
	}
	f[x]+=y;
	f[x]+=s;
}

void dfs1(int x){
	vis1[x]=1;
	for(int i=0;i<g[x].size();i++){
		if(!vis1[g[x][i]]){
			f[g[x][i]]=f[x]+n-cnt[g[x][i]]*2;
			sum+=f[g[x][i]]-g[g[x][i]].size()*2+n-1;
			dfs1(g[x][i]);
			vis1[g[x][i]]=0;
		}
	}
}

int32_t main() {
	cin >> n;
	for(int i=0;i<n-1;i++){
		int x;
		cin>>x;
		g[i+1].emplace_back(x);
		g[x].emplace_back(i+1);
	}
	dfs(n,0);
	sum+=f[n]-g[n].size()*2+n-1;
	dfs1(n);
	sum/=2;
	int t=(n-1)*(n-2)/2;
	int gg=gcd(t,sum);
	cout<<sum/gg<<'/'<<t/gg<<endl;
}


第一次遇到限制空间的题,故一直RE,最后是卡空间过的。实际上可以遍历两次来节约空间,若存在\(a_i=a_j\),因为数列是递推的,则必存在\(a_k=a_n\),则可以先遍历一遍算出\(a_n\),再遍历第二遍来判断是否存在\(a_k=a_n\),这样就不需要存储计算过的\(a_i\)来判重。

随机序列检测

题意:此题空间限制为4MB。整数序列满足\(a_i = (Aa_{i−1}^2 + Ba_{i−1} + C) mod P, i > 0\),给定$ n, a_0, A, B, C, P$,判定这个序列中是否存在重复的数字?

代码

#include <bits/stdc++.h>
#define ll long long
#define MOD 998244353
using namespace std;

map<int,int>hm;
ll n,A,B,C,f=0;
int P,a0,an;

int32_t main() {
	int T = 1;
	cin >> T;
	while (T--) {
		cin>>n>>a0>>A>>B>>C>>P;
		an=a0;
		f=0;
		for(int i=1;i<=n;i++){
			an=(((A*an)%P*an)%P+(B*an)%P+C)%P;
		}
		if(a0==an){
			f=1;
		}
		for(int i=1;i<=n-1;i++){
			a0=(((A*a0)%P*a0)%P+(B*a0)%P+C)%P;
			if(a0==an||f){
				f=1;
				break;
			}
		}
		if(f)cout<<"Repetitive\n";
		else cout<<"Different\n";
	}
}



posted @ 2024-03-24 13:50  ptlks  阅读(18)  评论(0编辑  收藏  举报