2025.7.30 CSP-S模拟赛30

好多神犇都走了……侥幸拿到了rk2

T1 天才俱乐部

非常简单的数学题,考虑模运算的性质,\(a\) \(mod\) \(b = a - \lfloor \frac{a}{b} \rfloor\)

所以 \(s = \sum_{i=1}^{n} (a_i\) \(mod\) \(k) = \sum_{i=1}^{n} a_i - \lfloor \frac{a_i}{k} \rfloor = (\sum_{i=1}^{n} a_i) - k \sum_{i=1}^{n} \lfloor \frac{a_i}{k} \rfloor\)

\(k \sum_{i=1}^{n} \lfloor \frac{a_i}{k} \rfloor = (\sum_{i=1}^{n} a_i) - s\) , 也就是 \(k \mid (\sum_{i=1}^{n} a_i) - s\)

所以我们可以直接枚举 \((\sum_{i=1}^{n} a_i) - s\) 的所有因数,再暴力 \(O(n)\) 检查;

注意特判当 \((\sum_{i=1}^{n} a_i) = s\) 的时候,一定存在一个极大的 \(k\) 满足所有 \(a_i<k\) ,直接输出YES即可;(出题人在90%的测试点中都放了这样一组数据,导致很多人挂了90分)

总时间复杂度 \(O(tn \sqrt{ \sum_{i=1}^{n} a_i} )\) ,放上代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long 
int t,n,s;
int a[105],sum,cz,flag;
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>t;
	while(t--){
		cin>>n>>s;sum=0;
		for(int i=1;i<=n;i++){
			cin>>a[i];sum+=a[i];
		} 
		cz=sum-s,flag=0;
		if(cz<0){
			cout<<"NO\n";
			continue;
		}
		if(cz==0){
			cout<<"YES\n";
			continue;
		}
		for(int i=1;i*i<=cz;i++){
			if(cz%i==0){
				int tot=0;
				for(int j=1;j<=n;j++){
					tot+=a[j]/i;
				}
				if(tot*i==cz) flag=1;
				if(flag) break;
				if(i*i!=cz){
					tot=0;
					for(int j=1;j<=n;j++){
						tot+=a[j]/(cz/i);
					}
					if(tot*(cz/i)==cz) flag=1;
				}
				if(flag) break;
			}
		}
		if(flag) cout<<"YES\n";
		else cout<<"NO\n";
	}
	return 0;
}

T2 实战教学

赛事写了一个伪的贪心竟然过了,不过经过wyl打瓦长达一个多小时的hack被艹飞了;

其实思路已经跟正解很像了,我们将 \(a\) 数组从大到小排序,再将 \(b\) 数组与其一一对应,二分答案枚举;因为 \(a\) 数组从大到小排序了,所以从前往后每一个 \(a_i\) 我们必然希望其在之前已经被选过,设二分结果为 \(mid\) ,当前枚举到 \(i\) ,我们要寻找对于每一个 \(j\) 满足 $a_i+b_j \leq mid $ ,且 \(a_j\) 最大的一对,也就是我们遇到的第一个满足条件的数对;

正解是用set维护,但是本题数据较水,可以用一个玄学 \(O(n^2)\) 艹过去;

#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
#define int long long
int n;
int maxa,maxb;
struct node{
	int a,b;
}e[MAXN<<1];
bool cmp(node x,node y){
	return x.a>y.a;
}
int vis[MAXN];int l,r,ans;
bool check(int mid){
	memset(vis,0,sizeof vis);
	for(int i=1;i<2*n;i++){
		if(vis[i]) continue;
		if(e[i].a+e[i].b>mid) return 0;
		vis[i]=1;
		for(int j=i+1;j<=2*n;j++){
			if(e[j].b<=mid-e[i].a){
				vis[j]=1;
				break;
			}
			else if(j==2*n) return 0;
		} 
	}
	return 1;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>n;
	for(int i=1;i<=2*n;i++)
		cin>>e[i].a;
	for(int i=1;i<=2*n;i++)
		cin>>e[i].b;
	sort(e+1,e+2*n+1,cmp);
	int l=0,r=INT_MAX;
	while(l<r){
		int mid=l+r>>1;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	cout<<l;
	return 0;
}

T3 穿越银匙之门

无根树不好操作,我们考虑将其变为有根树;

分别枚举A树和B树上的根,跑两遍dfs;我们容易发现,一个节点需要被操作当且仅当它在A中的父亲和它在B中的父亲不同,而如果一个点不需要被操作,但他的父亲需要被操作,那么显然无解;

我们枚举所有需要被操作的点,将其向B树上的父亲连边,再将其向其所有儿子连边;这可以理解为一个点要被操作,首先依赖于它在B树上的父亲被操作好(或本来就无需操作),并且依赖于自己的儿子全部被操作过;

这样的依赖组成了一个先后关系,我们在新连的边中,即若干个联通块中找环,如果存在环,就是存在没有起点的依赖关系,显然也无解;

如果有解,那么直接统计所有需要操作的点的数量,这就是答案;

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=100;
int t,n,f[MAXN][2];
int res;
vector<int> e[2][MAXN],g[MAXN];
void dfs(int x,int fa,bool flag){
	f[x][flag]=fa;
	for(int i=0;i<e[flag][x].size();i++){
		int y=e[flag][x][i];
		if(y!=fa)
			dfs(y,x,flag);
	}
	return ;
} 
int ned[MAXN],can[MAXN];
void add(int x,int fa){
	if(f[x][0]==f[x][1]) can[x]=0;
	else can[x]=1,g[x].push_back(f[x][1]);
	for(int i=0;i<e[0][x].size();i++){
		int y=e[0][x][i];
		if(y==fa) continue;
		add(y,x);
		if(f[x][0]!=f[x][1]) g[x].push_back(y);
		if(!can[y]) can[x]=0;
	}
	return ;
}
int visf[MAXN],viss[MAXN];
bool zh;
void ph(int x){
	if(zh) return ;
	visf[x]=viss[x]=1;
	for(int i=0;i<g[x].size();i++){
		int y=g[x][i];
		if(viss[y]){
			zh=1;break;
		}
		ph(y);
	}
	viss[x]=0;
	return ;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin>>t;
	while(t--){
		cin>>n;
		for(int i=1;i<=n;i++)
			e[0][i].clear(),e[1][i].clear();
		memset(can,0,sizeof can);
		memset(visf,0,sizeof visf);
		for(int i=1;i<n;i++){
			int u,v;cin>>u>>v;
			e[0][u].push_back(v);
			e[0][v].push_back(u); 
		}
		for(int i=1;i<n;i++){
			int u,v;cin>>u>>v;
			e[1][u].push_back(v);
			e[1][v].push_back(u);
		}
		res=1e9;
		for(int rt_a=1;rt_a<=n;rt_a++){
			for(int rt_b=1;rt_b<=n;rt_b++){
				for(int i=1;i<=n;i++) g[i].clear();
				dfs(rt_a,0,0);
				dfs(rt_b,0,1);
				add(rt_a,0);
				bool flag=1;
				for(int i=1;i<=n;i++){
					if(f[i][0]!=f[i][1]&&!can[i]){
						flag=0;break;
					}
				}
				if(!flag) continue;
				zh=0;
				memset(visf,0,sizeof visf);
				for(int i=1;i<=n;i++){
					if(!visf[i]){
						memset(viss,0,sizeof viss);
						ph(i);
					}
				} 
				if(zh) continue;
				int ans=0;
				for(int i=1;i<=n;i++)
					if(f[i][0]!=f[i][1]) ++ans;
				res=min(res,ans);
			}
		}
		if(res<1e9) cout<<res<<"\n";
		else cout<<"-1\n";
	}
	return 0;
}

T4 绳网委托

没改,直接看题解上写的吧

image
image

posted @ 2025-08-13 10:47  zhangch_qwq  阅读(15)  评论(0)    收藏  举报