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 绳网委托
没改,直接看题解上写的吧


本文来自博客园,作者:zhangch_qwq,转载请注明原文链接:https://www.cnblogs.com/zhangchenhua-awa/p/19035338

浙公网安备 33010602011771号