之江学院第0届校赛题解

之江学院第0届校赛题解

qwb与支教

可以容斥算出报到数字t的时候,需要多少名学生,然后二分这个t就行

算lcm的时候,注意会超过long long ,可以用double判断下,或者__int128(不过好像并没有这样的数据)

qwb与矩阵

nmlogm的dp

勤劳的ACgirls

用隔板法算出答案是C(n+(1-k)*m-1,m-1),然后算出因子5和因子2的个数,取小的那个

	int m,n,r;
	while(scanf("%d%d%d",&m,&n,&r)==3){
		LL x=m-1,y=n+(LL)(1-r)*m-1;
		int ans=0;
		if(x>y||y<=0){
			ans=0;
		}else{
			int c2=0,c5=0;
			for(LL i=2;i<=y;i=i*2){
				c2+=y/i-(y-x)/i-x/i;
			}
			for(LL i=5;i<=y;i=i*5){
				c5+=y/i-(y-x)/i-x/i;
			}
			
			ans=min(c2,c5);
		}
		printf("%d\n",ans);
	}

qwb与神奇的序列

用数列知识 容易算出答案是(3^n+1)/2

本题要求mod1e8,2和1e8不互质,没有逆元

易证 A/C%B=A%(B*C)/C

那在快速幂的时候 %2e8就行了

qwb和李主席

折半搜索+二分查找,注意可能会因为浮点数误差导致WA,解决方法是一开始*200化成LL,

具体操作就是

double x;
scanf("%lf",&x);
a[i]=round(x*200);
//或者a[i]=x*200+0.1;

也可以直接用long double过。

有些方法可以用double过,反正我的不可以。

qwb has a lot of Coins

唯一的英文题一定是个水题,先手只要想办法让异或值等于0就行。

int n;
while(scanf("%d",&n)==1){
	int x=0;
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
		x^=a[i];	
	}
	int ans=0;
	if(x!=0)
		for(int i=0;i<n;i++){
			int y=x^a[i];
			if(a[i]>=y)ans++;
		}
	printf("%d\n",ans);
}

qwb去面试怕大家爆0,特意加的水题。很容易看出分成2和3最好,并且6=2+2+2=3+3,2*2*2=8,3*3=9,说明尽量分成3.

也可以这样想,如果把问题改成连续的,也就是能分成小数,显然是每个数一样的时候最好,
也就是算 (n/x)^x的最大值,通过求导算出n/x=e的时候有极值,所以要尽量分成3和2


int _;scanf("%d",&_);
while(_--){
	int n;scanf("%d",&n);
	int ans;
	if(n==1){
		ans=1;
	}else{
		if(n%3==0){
			ans=pow_mod(3,n/3);
		}else if(n%3==1){
			ans=pow_mod(3,n/3-1)*4%mod;
		}else{
			ans=pow_mod(3,n/3)*2%mod;
		}
	}
	printf("%d\n",ans);
}
qwb与学姐

题目意思是查询图上两点的瓶颈路大小,这个训练指南上有讲解。

先是求最大生成树,然后求树上两点路径的最小值,用LCA倍增法就可以了,

时间复杂度O(mlogm+nlogn+klogn)

template <class T> inline void umin(T &a,T b){a=min(a,b);}
template <class T> inline void umax(T &a,T b){a=max(a,b);}
const int N=50005;
struct Bian{  
	int u;    
	int v;
	int w;
};
int p[N],ra[N]; 
Bian  bian[200005];
vector<pii> G[N];
bool cmp(const Bian &p1,const Bian &p2){
	return p1.w>p2.w;
}
int find(int x){
	return p[x]==x?x:p[x]=find(p[x]);
}
int Union(int x,int y) {
	x=find(x);
	y=find(y);
	if(x==y)return 0;
	if(ra[x]>ra[y]) {
		p[y]=x;
	}else{
		if(ra[x]==ra[y])ra[y]++;
		p[x]=y;
	}
	return 1;
}
void Kruskal(int kn,int km){
	for(int i=1;i<=kn;i++){
	     p[i]=i;   
    }
	sort(bian,bian+km,cmp);
	for(int i=0;i<km;i++){
		if(Union(bian[i].u,bian[i].v)){
			G[bian[i].u].push_back({bian[i].v,bian[i].w});
			G[bian[i].v].push_back({bian[i].u,bian[i].w});
		}
	}
}



int d[N][20],f[N][20];
int dep[N];
void dfs(int u,int fa){
	dep[u]=dep[fa]+1;
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i].ff;
		if(v==fa)continue;
		f[v][0]=u;
		d[v][0]=G[u][i].ss;
		dfs(v,u);
	}
}
int main() {
#ifndef ONLINE_JUDGE
	//freopen("sb.txt","r",stdin);
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
#endif
	int n,m,q;
	scanf("%d%d%d",&n,&m,&q);
	for(int i=0;i<m;i++){
		scanf("%d%d%d",&bian[i].u,&bian[i].v,&bian[i].w);
	}
	Kruskal(n,m);
	dep[1]=1;
	dfs(1,0);
	int wc=0;//log深度 
	for(int i=1;;wc++){
		i<<=1;
		if(i>n)break;
	} 
	for(int j=1;j<=wc;j++){
		for(int i=1;i<=n;i++){
			f[i][j]=f[f[i][j-1]][j-1];
            d[i][j]=min(d[i][j-1],d[f[i][j-1]][j-1]);
		}
	}
	while(q--){
		int x,y;
		scanf("%d%d",&x,&y);
		int ans=INF;
		if(dep[x]<dep[y])swap(x,y);
		for(int i=wc;i>=0;i--){
			if(dep[f[x][i]]>=dep[y]){
				umin(ans,d[x][i]);
				x=f[x][i];
				if(dep[x]==dep[y])break;
			}
		}
		if(x!=y){
			for(int i=wc;i>=0;i--){
				if(f[x][i]!=f[y][i]){
					umin(ans,d[x][i]);
					umin(ans,d[y][i]);
					x=f[x][i];
					y=f[y][i];
				} 
			}
			umin(ans,d[x][0]);
			umin(ans,d[y][0]);
		}
		printf("%d\n",ans);
	}
	return 0;
}

也可以通过重建树,控制树高为logn,不用倍增法直接暴力lca。

直接在算最大生成树的时候,连接两个并查集的根,因为是从大到小取边的,所以两点间的最小值不会受影响。

注意并查集要安秩合并!

LL mod=1e9+7;
const int N=50005;

struct Bian { 
	int u;
	int v;
	int w;
};
int p[N]; 
Bian  bian[200005];
vector<pii> G[N];
bool cmp(const Bian &p1,const Bian &p2){
	return p1.w>p2.w;
}
int find(int x) {
	return p[x]==x?x:p[x]=find(p[x]);
}

int ra[N];
void Kruskal(int kn,int km) { 
	for(int i=1; i<=kn; i++) {
		p[i]=i;
		ra[i]=0;
	}
	sort(bian,bian+km,cmp);
	for(int i=0; i<km; i++) {
		int x=bian[i].u,y=bian[i].v;
		x=find(x);
		y=find(y);
		if(x==y)continue;
		if(ra[x]>ra[y]) {
			p[y]=x;
			G[x].push_back({y,bian[i].w});
		}else{
			if(ra[x]==ra[y])ra[y]++;
			G[y].push_back({x,bian[i].w});
			p[x]=y;
		}
	}
}
int d[N],f[N];
int dep[N];
void dfs(int u,int fa) {
	dep[u]=dep[fa]+1;
	for(int i=0; i<G[u].size(); i++) {
		int v=G[u][i].ff;
		if(v==fa)continue;
		f[v]=u;
		d[v]=G[u][i].ss;
		dfs(v,u);
	}
}
int main() {
#ifndef ONLINE_JUDGE
	freopen("t3.in","r",stdin);
	freopen("t3.out","w",stdout);
#endif
	int n,m,q;
	scanf("%d%d%d",&n,&m,&q);
	for(int i=0; i<m; i++) {
		scanf("%d%d%d",&bian[i].u,&bian[i].v,&bian[i].w);
	}
	Kruskal(n,m);
	dep[find(1)]=1;
	dfs(find(1),0);
	while(q--) {
		int x,y;
		scanf("%d%d",&x,&y);
		int ans=INF;
		if(dep[x]<dep[y])swap(x,y);
		while(dep[x]>dep[y]) {
			umin(ans,d[x]);
			x=f[x];
		}
		while(x!=y) {
			umin(ans,d[x]);
			umin(ans,d[y]);
			x=f[x];
			y=f[y];
		}
		printf("%d\n",ans);
	}
	return 0;
}

qwb VS 去污棒

原题是BZOJ-3261,就当解放权限题了。

可持久化字典树,我也要去学学。

qwb又偷懒了

用两个树状数组分别保存收入和人数,坑点在收入为0的情况,可以记录一下0的个数,或者直接平移1。

qwb与小数

a/b的第n位可以由第n-1位求出,第n-1位除的余数乘10再除以b就是第n位的数,答案就是a*pow_mod(10,n-1.b)%b*10/b或者a*pow_mod(10,n,10*b)/b%10。快速幂的时候模取b即可。
by 不愿意透露名字的答疑员水明

我是

ans=(__int128)a*pow_mod(10,n,(__int128)10*b)/b%10;
qwb与整数对
case=1的时候很容易可以想到一个n^2的暴力
那么在case比较大的时候,把所有case根据n的数值进行排序。再离线处理,枚举每一组(a,b),穷举整数t∈[-20000,20000],当符合条件(a^2+b^2+t)%ab==0时,ans[t]++,最后根据case的顺序从离线处理中获取答案,复杂度O(∑(i=1..n,j=2..n) (40000/ab)) + O(n^1.5)
by 🍋柠檬

我的方法如下,复杂度比较玄学,900ms...

vector<int> G[N][N];

for(int i=1;i<1000;i++){
	for(int j=i+1;j<1000;j++){
		int m=i-j*j%i;
		if(m==i)m=0;
		G[i][m].push_back(j);
	}
}
int n,m;
int cas=0;
while(scanf("%d%d",&n,&m),n!=0||m!=0){
	int ans=0;
	for(int i=1;i<n;i++){
		int t=m%i;
		if(t<0)t+=i;
		for(auto x:G[i][t]){
			if(x>=n)break;
			if((i*i+x*x+m)%(x*i)==0)ans++;
		}
	}
	printf("Case %d: %d\n",++cas,ans);

}

qwb与二叉树
记忆化搜索暴力过,时间复杂度O(n^4)
LL dp[55][55];
LL dfs(int x,int y){
	if(dp[x][y]!=-1)return dp[x][y];
	dp[x][y]=0;
	//if(y>=x)return dp[x][y]=0;
	for(int i=0;i<=x-1;i++){
		for(int j=0;j<=i&&j<=y;j++){
			dp[x][y]+=dfs(i,j)*dfs(x-1-i,y-j);
			dp[x][y]%=mod;
		}
	}
	return dp[x][y];
}
int main() {
#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
#endif
	int n,m;
	memset(dp,-1,sizeof dp);
	dp[0][0]=1;
	dp[1][0]=0;
	dp[1][1]=1;
	while(scanf("%d%d",&n,&m)==2){
		printf("%lld\n",dfs(n,m));
	}
	return 0;
}


jnxxhzz的博客 - 博客频道 - CSDN.NET 这个博客里也有本次比赛的题解

相关问题 如何评价之江学院第0届校赛? - 知乎