231113校内赛

T1 项链

首先一个求最大的最小就很容易想到二分

发现我们可以通过 \(\mathcal O(n)\) 来方便的求出如何删除,总时间复杂度只有 \(\mathcal O(n\log n)\)

因为这是一个环,我们需要特殊判断首尾相接时的状况

对于最后一个和第一个的比较一定只会删一次

证明如下:

\(a_1+a_2\le x\)\(a_1+a_n > x\)

我们删去小的那个之后

如果 \(a_1 >a_n\) 显然 \(a_n+a_2 < x\)

如果 \(a_n \ge a_1\) 那么剩下的还是 \(a_1+a_2\) 仍然不可能再删

#include<bits/stdc++.h>
#define int long long
#define N 500010
using namespace std;
int n,m,tid,a[N],stk[N],top;
inline int check(int x){
	top = 0;
	for(int i = 1;i<=n;i++){
		if(stk[top]+a[i]>x){
			stk[top] = min(stk[top],a[i]);
			continue;
		}
		stk[++top] = a[i];
	}
	if(stk[1]+stk[top]>x) top--;
	return top;
}
signed main(){
	freopen("necklace.in","r",stdin);
	freopen("necklace.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>tid>>n>>m;
	for(int i = 1;i<=n;i++)
		cin>>a[i];
	int l = 0,r = 2e9,ans = 2e9;
	while(l<=r){
		int mid = (l+r)>>1;
		if(check(mid)<m) l = mid+1;
		else r = mid-1,ans = mid;
	}
	cout<<ans;
	return 0;
}

T2 计树

考虑 \(dp\) ,设 \(f_{i,j,k}\) 表示考虑了前 \(i\) 个节点,有 \(j\) 个节点没有父亲,即当前图为有 \(k\) 棵树的森林,且前 \(i\) 个点缺少 \(k\) 个儿子,转移时设第 \(i+1\) 个节点儿子数量为 \(l\)

分类讨论一下:

\(l = 0\)

  1. 如果新开一棵树:\(f_{i+1,j+1,k} = f_{i,j,k}\)

  2. 如果接在某个缺儿子的节点下面 \(f_{i+1,j,k} = k \times f_{i,j,k}\)

\(l = 1\)

\(l = 0\) 的转移方式一样,但两个转移时都要乘二,因为有左右儿子之分

\(l = 2\)

\(l=0\) 时相同,且有额外的两种方式

  1. 将某个没有父亲的节点接在它下面 \(f_{i+1,j,k+1}=2 \times j \times f_{i,j,k}\)

  2. 将某个没有父亲的节点接在它下面,并且它接在某个缺儿子的节点下面 \(f_{i+1,j-1,k} = 2\times (j-1)\times k \times f_{i,j,k}\)\(j-1\) 是因为你已经确定了哪个缺儿子的节点了,而这个节点就不能作为一个没有父亲的点接在你下面了

时间复杂度 \(\mathcal O(Tn^3)\)

#include<bits/stdc++.h>
#define int long long
#define N 310
#define mod ((int)1e9+7)
using namespace std;
int n,l[N],r[N],f[N][N][N];
int ksm(int x,int y){
	int res = 1;
	while(y){
		if(y&1) res = res*x%mod;
		x = x*x%mod;
		y>>=1;
	}
	return res;
}
signed main(){
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	int T,tid;cin>>tid>>T; 
	while(T--){
		memset(f,0,sizeof(f));
		cin>>n;
		for(int i = 1;i<=n;i++)
			cin>>l[i]>>r[i];
		f[0][0][0] = 1;
		for(int i = 1;i<=n;i++){
			for(int j = 0;j<i;j++){
				for(int k = 0;k<=n;k++){
					if(!f[i-1][j][k]) continue;
					if(l[i]==0){
						f[i][j+1][k] = (f[i][j+1][k]+f[i-1][j][k])%mod;
						if(k) f[i][j][k-1] = (f[i][j][k-1]+f[i-1][j][k]*k%mod)%mod;
					}
					if(l[i]<=1&&r[i]>=1){
						f[i][j+1][k+1] = (f[i][j+1][k+1]+2*f[i-1][j][k])%mod;
						f[i][j][k] = (f[i][j][k]+2*f[i-1][j][k]*k%mod)%mod;
					}
					if(r[i]==2){
						f[i][j+1][k+2] = (f[i][j+1][k+2]+f[i-1][j][k])%mod;
						f[i][j][k+1] = (f[i][j][k+1]+f[i-1][j][k]*k%mod)%mod;
						f[i][j][k+1] = (f[i][j][k+1]+2*f[i-1][j][k]*j%mod)%mod;
						if(j) f[i][j-1][k] = (f[i][j-1][k]+2*(j-1)%mod*k%mod*f[i-1][j][k])%mod;
					}
				}
			}
		}
		cout<<f[n][1][0]<<"\n";
	}
	return 0;
}
posted @ 2023-11-13 16:20  cztq  阅读(12)  评论(0编辑  收藏  举报