补题报告之S班暑训第二场

成绩

image

比赛经过

糟糕记不清了?

\(\text{A}\) 题,结论很显然,不出意外应该是很快就搞出来了,但是没有考虑所给的子图可能不连通!挂成 \(\text{50}\) 了?

\(\text{B}\) 题,一眼 \(\text{DP}\) 事实证明我是对的。但是我对一个子问题 \(\text{DP}\)。考虑的是 \(0\) 时刻的方案选取数,本来想用 \(bitset\) 水过去,奈何不会搞。(没想到直接对答案 \(\text{DP}\) 时间复杂度更优秀?)

\(\text{C}\) 题,我去,二次函数上凸壳?这不会啊,暴力(对了 \(32\) 分然后一分不给?)

\(\text{D}\) 题,从数据范围的特殊限制,就已经猜到和阶有关了(特殊性质:保证是 \(p\) 的原根),大概是个循环类似的题吧(蒙对了???)。然后不会做,特殊性质打表拿了 \(10\) 分。

赛后补题+分析

\(\text{A}\) Tree

简要/形式化题意

给定一棵弱连通树的子图,记一棵弱连通树的值为:给弱连通树赋边权 \(0/1\),使得 \(1\) 到任意某个可达结点的边权和大于 \(0\)。求这颗弱连通树的值对 \(p\) 取余的最大值。

题解

  • 树确定时,答案为 \(2^{n-1-k}\)\(k\) 为从 \(1\) 出发可达结点中的相邻结点个数。
  • 给定子图后,\(n\) 个结点 \(cnt\) 个连通块。不属于 \(1\) 结点所在连通块的每个连通块,要么选择一个结点作为 \(1\) 的可达结点中的相邻结点,要么都不是。因此,这样的 \(cnt-1\) 个连通块对 \(k\) 的贡献为 \(0/1\)。因此 \(k\) 的范围为 \([sonbase,sonbase+cnt-1]\)\(sonbase\)\(1\) 所在连通块的可达结点中的相邻结点的个数。暴力枚举即可。时间复杂度 \(O(n)\)

AC code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int n,m,p,u,v,sonbase,Ans,cnt;
int flag[N];
int ksm(int a,int b,int P) {
	int ans=1%P;
	for(;b;b>>=1) {
		if(b&1) ans=ans*a%P;
		a=a*a%P;
	}
	return ans;
}
struct node {
    int fa[N];
    void cleanr(int n) { 
		for(int i=1;i<=n;i++) fa[i]=i;
	}
    int find(int x) { 
    	if(x==fa[x]) return x;
		return fa[x]=find(fa[x]); 
	}
    void merge(int x,int y) { 
    	int fx=find(x),fy=find(y);
    	if(fx!=fy) fa[fx]=fy; 
	}
}BCJ;
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m>>p;
	BCJ.cleanr(n);
	for(int i=1;i<=m;i++) {
		cin>>u>>v;
		BCJ.merge(u,v);
		if(u==1) sonbase++;
	}
	for(int i=1;i<=n;i++) flag[BCJ.find(i)]=1;
	for(int i=1;i<=n;i++) cnt+=flag[i];
	for(int i=sonbase;i<=sonbase+cnt-1;i++) 
		Ans=max(Ans,ksm(2,n-1-i,p));
	cout<<Ans;
	return 0;
}

\(\text{B}\) Game

简要/形式化题意

给定一个大小为 \(n\) 集合 \(S\)。先选取其子集 \(T\),使得 \(T\) 内元素之和为 \(m\)。之后 \(k\) 轮,每轮选择剩下 \(n-|T|\) 个元素组成集合的一个子集放入 \(T\) 中。问:使得最后 \(|T|=n\) 的方案数。

题解

  • 首先,答案为:

\[\sum\limits_{T \subset S}{\left(\left[\sum\limits_{x \in T}{x=m}\right] \times k^{n-|T|}\right)} \]

  • 即上面这个式子为 \(dp_{n,m}\)。那么有

\[dp_{i,j}=dp_{i-1,j}+\left[j \ge a_i\right] \times dp_{i-1,j-a_i} \times \dfrac{1}{k} \]

  • 时间复杂度 \(O(Tnm)\)

AC code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=5e3+10;
const int mod=1e9+7;
int T;
int n,m,k;
int a[N],dp[N][N],ans;
int ksm(int a,int b,int P) {
	int ans=1%P;
	for(;b;b>>=1) {
		if(b&1) ans=ans*a%P;
		a=a*a%P;
	}
	return ans;
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>T;
	while(T--) {
		cin>>n>>m>>k;
		for(int i=1;i<=n;i++) cin>>a[i];
		memset(dp,0,sizeof(dp));
		dp[0][0]=ksm(k,n,mod);
		int inv=ksm(k,mod-2,mod);
		for(int i=1;i<=n;i++)
			for(int j=0;j<=m;j++) {
				dp[i][j]=dp[i-1][j];
				if(j>=a[i]) dp[i][j]=(dp[i][j]+dp[i-1][j-a[i]]*inv%mod)%mod;
			}
		cout<<dp[n][m]<<endl;
	}
	return 0;
}

\(\text{C}\) Funciton

简要/形式化题意

二维平面上给定 \(n\) 个点,每两个点确定一个二次函数:\(y=x^2+bx+c\)。问有多少条二次函数,是的所有点都不在二次函数的严格上方。

题解

  • 如果是一次函数,不难想到是维护一个凸包,可使用单调栈,时间复杂度 \(O(n)\)

  • 对于二次函数,即两个点为 \((x_1,y_1)\)\((x_2,y_2)\)。则有:\(y_1-x_1^2=bx_1+c\)\(y_2-x_2^2=bx_2+c\)。可以看做,\((x_1,y_1-x_1^2)\)\((x_2,y_2-x_2^2)\) 确定了一个一次函数。那么按照上述做法求凸包就好了。

AC code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int n,ans,st[N],top,cnt;
struct node {
	int x,y;
}a[N],b[N];
map<pair<double,double>,int>Map;
bool cmp(node x,node y) {
	return x.x<y.x||(x.x==y.x&&x.y>y.y);
}
double slope(node x,node y) {
	return (y.y-x.y)*1.0/(y.x-x.x);
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++) { 
		cin>>a[i].x>>a[i].y;
		a[i].y-=a[i].x*a[i].x; 
	} 
	sort(a+1,a+n+1,cmp);
	b[1]=a[1],cnt=1;
	for(int i=2;i<=n;i++) 
		if(a[i].x!=a[i-1].x) b[++cnt]=a[i];
	n=cnt;
	for(int i=1;i<=n;i++) {
		while(top>1&&slope(b[st[top-1]],b[st[top]])<=slope(b[st[top]],b[i])) top--;
		st[++top]=i;
	}
	cout<<top-1;
	return 0;
}

\(\text{D}\) path

简要/形式化题意

给定 \(p\)\(k\)\(q\)。对于任意 \(0 \le x < p\)\(0 \le i <k\)\(x\)\((kx+i) \bmod p\) 连一条边权为 \(i\) 的有向边。\(q\) 次询问两点之间的最短路。

题解

  • 对于 \(i\) 等于 \(0\)。我们可以认为他们的边权都是无效的。设 \(\delta_{p}{(k)}=s\)。则我们可以将原图划分为 \(\dfrac{p}{s}\) 个无效集合,对他们缩点,得到的图跑 \(\text{Floyd}\)。时间复杂度 \(O(\dfrac{p^3}{s^3})\)

  • 另一种方法是。我们推导出一个结论:\(u\)\(v\) 的最短路与 \(0\)\(u-k^cv\) 的最短路长度在模 \(p\) 意义下等价。同时 \(0 \le c <s\) 。通过 \(0/1\) \(\text{bfs}\) 预处理出 \(0\) 到所有点的最短路,询问在 \(O(qs)\) 的时间复杂度下全部求出。

  • 至此,我们可以采用根号分治,由均值不等式,我们可以的到最终的平衡复杂度为 \(O(p^{\frac{3}{4}}q^{\frac{3}{4}})\)。分解值为 \(s=\dfrac{p^{\frac{3}{4}}}{q^{\frac{1}{4}}}\)。计算发现时间复杂度相对于 \(\text{1e8}\) 都是绰绰有余的。

AC code

先咕着~

考后反思

其实还行,就是没有给大样例,\(\text{B}\) 题理论上能多骗点分。但是没调出来。还有就是不要想复杂!按常理思考(对子问题 \(\text{dp}\) 可还行 满级嘲讽)。

结尾

咕咕咕,代码调不出来!!!!!

posted @ 2023-07-25 15:50  2021hych  阅读(42)  评论(0)    收藏  举报