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

比赛经过
糟糕记不清了?
\(\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\) 的方案数。
题解
- 首先,答案为:
- 即上面这个式子为 \(dp_{n,m}\)。那么有
- 时间复杂度 \(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}\) 可还行 满级嘲讽)。
结尾
咕咕咕,代码调不出来!!!!!

浙公网安备 33010602011771号