曲阜师范大学2023年暑期大一新生排位赛 题解

目录

A (1). Sum 详细点击:sum      //整除分块

B (2). Sort

C (3). String                              //字符串dp

D (4). Factor                ​​​​​​​        ​​​​​​​     //素数筛变式

E (5). Tree                ​​​​​​​        ​​​​​​​        //树形dp

F (6). Geometry                        //几何

G (7). Graph                         ​​​​​​​    //二分答案

H (8). Line                                //贪心

I (9). And / Or                       ​​​​​​​    //位运算

J (10). Mov                ​​​​​​​               //模拟


A (1). Sum 详细点击:sum
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)

ll T,x,y;

void solve() {
	ll res=0;
	cin>>x>>y;
	ll i=min((ll)sqrt(x),y);
	while(i*i+i+1>x)
		i--;
	res=(1+i)*i/2;
	for(ll l=i+1,r; l<=y,l+1<=x; l=r+1) {
		r=x/(x/(l+1))-1;
		r=min(r,y);
		if(l>r)
			break;
		res+=x/(l+1)*(r-l+1);
	}
	cout<<res<<"\n";
}

int main() {
	IOS;
	cin>>T;
	while(T--)
		solve();
	return 0;
}
B (2). Sort

使用stable_sort强行卡过,优化可了解:sort 学长Ashy深情讲解

#include<bits/stdc++.h>
using namespace std;

struct node {
	long long x,y;
} d[100001];
long long e[100001];
long long n,q,t,u,v;

bool cmp(node a,node b) {
	return a.x==b.x?a.y<b.y:a.x<b.x;
}

int main() {
    ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>q;
	for(long long i=1; i<=n; i++)
		cin>>d[i].x,d[i].y=i;
	/*
	for(int i=1; i<=n; i++)
		cout<<d[i].x<<" "<<d[i].y<<"\n";
	*/
	stable_sort(d+1,d+1+n,cmp);
	for(int i=1; i<=n; ++i)
		e[d[i].y]=i;
	while(q--) {
		cin>>t;
		if(t==1) {
			cin>>u>>v;
			d[e[u]].x=v;
			stable_sort(d+1,d+1+n,cmp);
			for(int i=1; i<=n; ++i)
				e[d[i].y]=i;
		} else {
			cin>>u;
			cout<<e[u]<<"\n";
		}
	}
	return 0;
}

在这提一下stable_sort和sort的区别,单纯从性能来讲sort性能更好,因为stable_sort要维护数据的稳定性,丧失了一部分性能,但在大部分数据顺序不变的情况下,stable_sort要比sort快很多

C (3). String

字符串dp,即区间dp

#include<bits/stdc++.h>
using namespace std;
//最长回文串子序列

int n;
string s;
int dp[2100][2100];
//字符串s在区间[i, j]范围内的最长回文子序列的长度
//dp[i][j] = dp[i+1][j-1] + 2;
//dp[i][j] = (dp[i+1][j] > dp[i][j-1]) ? dp[i+1][j] : dp[i][j-1];

int main() {
	cin>>n>>s;
	for (int i=0;i<n;i++)
		dp[i][i]=1;
	for (int len=2;len<=n;len++) {
		for (int i=0;i<=n-len;i++) {
			int j=i+len-1;
			if (s[i]==s[j]) {
				dp[i][j]=dp[i+1][j-1] + 2;
			} else {
				dp[i][j]=(dp[i+1][j]>dp[i][j-1])?dp[i+1][j]:dp[i][j-1];
			}
		}
	}
	cout<<n-dp[0][n-1];
	return 0;
}
D (4). Factor

用埃式筛暴力筛出来的,时间复杂度为O(nlogn)

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+1;

int n,a,ans;
bool vis[maxn];

int main() {
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1; i<=n; i++)
		cin>>a,vis[a]=true;
	for(int i=1; i<=maxn; i++)
		for(int j=i; j<=maxn; j+=i)
			if(vis[j]) {
				ans++;
				break;
			}
	cout<<ans;
	return 0;
}
E (5). Tree

树形DP模板题

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e6+10;

ll a[N],u,v;
ll f[N],tot;
struct Edge {
	int to,next;
} edges[N];
int head[N],edge_len,n;

void Add(int from,int to) {
	edges[++edge_len].next=head[from];
	edges[edge_len].to=to;
	head[from]=edge_len;
}
void Dfs(ll e,ll fa) {
	bool flag=0;
	f[e]+=a[e];
	for(int i=head[e]; ~i; i=edges[i].next) {
		if(edges[i].to!=fa) {
			flag=1;
			Dfs(edges[i].to,e);
			f[e]+=f[edges[i].to];
		}
	}
}

int main() {
	memset(head,-1,sizeof head);
	cin>>n;
	for(int i=1; i<=n; i++)
		cin>>a[i],tot+=a[i];
	for(int i=1; i<n; i++) {
		cin>>u>>v;
		Add(u,v);
		Add(v,u);
	}
	Dfs(1,0);
	ll mx=0;
	for(int i=2; i<=n; i++)
		mx=max(mx,abs(f[i]-(tot-f[i])));
	cout<<mx;
}
F (6). Geometry

把梯形补成三角形 

 补出来的三角形与等腰三角形是相似三角形,通过三角形相似我们可以得出来

\frac{h+H}{\frac{a}{2}}=\frac{c}{r}

H+d=\sqrt{r^2+c^2}

\frac{h+H}{a}=\frac{H}{b}

通过以上三式解方程就可以了。

#include<bits/stdc++.h>
using namespace std;
//梯形补成三角形
//按照比求三角形高与H圆心到三角形顶点的距离d+H
//H=b/(a-b)*h
//c=r*h*2/(a-b)
//d+H=sqrt(c*c+r*r)

double r,a,b,c,h,H,d;

int main() {
	cin>>r>>a>>b>>h;
	if(2*r<b){
		cout<<"Drop";
		return 0;
	}
	H=b/(a-b)*h*1.0;
	c=r*h*2.0/(a-b);
	d=sqrt(c*c+r*r)-H;
	cout<<"Stuck\n";
	cout<<fixed<<setprecision(7)<<d;
	return 0;
}
G (7). Graph

二分答案,judge函数用于判断给定的时间t是否满足从起点x到终点y的路径存在。

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+10;
typedef long long ll;

int n,m,x,y;
int head[N],edge_len;
struct edge {
	int next,to;
	ll w;
} edges[N];
int u[N],v[N],w[N];
bool vis[N];

void Add(int from,int to,ll w) {
	edges[++edge_len].next=head[from];
	edges[edge_len].to=to;
	edges[edge_len].w=w;
	head[from]=edge_len;
}
void Dfs(int e) {
	if(vis[e])
		return;
	vis[e]=true;
	for(int i=head[e]; ~i; i=edges[i].next) {
		if(!vis[edges[i].to])
			Dfs(edges[i].to);
	}
}
bool judge(int t) {
    for(int i=0;i<=n;++i)
        head[i]=-1,vis[i]=false;
	edge_len=0;
	for(int i=0; i<m; ++i) {
		Add(u[i],v[i],w[i]);
		if(w[i]>t)
			continue;
		Add(v[i],u[i],w[i]);
	}
	Dfs(x);
	return vis[y];
}

int main() {
    ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);

	cin>>n>>m>>x>>y;
	for(int i=0; i<m; ++i)
		cin>>u[i]>>v[i]>>w[i];
	int l=0,r=1e9,mid;
	while(l<r) {
		mid=l+r>>1;
		if(judge(mid))
			r=mid;
		else
			l=mid+1;
	}
	cout<<l<<"\n";
	return 0;
}
H (8). Line

贪心的思想,按边的右端点排序,以第一个右端点向右扩大k,找到第一个超出此范围的左端点,并将其右端点作为新的lc

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

ll n,k,cnt;
struct node {
	ll l,r;
} d[1000001];

bool cmp(node a,node b) {
	return (a.r==b.r)?a.l<b.l:a.r<b.r;
}

int main() {
    ios::sync_with_stdio(false);
	cin.tie(0);

	cin>>n>>k;
	for (int i=0; i<n; i++)
		cin>>d[i].l>>d[i].r;
	sort(d,d+n,cmp);
	ll lr=d[0].r+k;
	for (int i=1; i<n; i++) {
		if(d[i].l<=lr){    
			continue;
        }
		lr=d[i].r+k;
		cnt++;
	}
	cout<<cnt+1;
	return 0;
}
I (9). And / Or

我们知道按位或是不进位加法,a|b\geq a,b 恒成立。

因此只要把每个数进行按位与操作就可以得到最大值

#include<bits/stdc++.h>
using namespace std;

int n,a[100001],ans;

int main() {
	cin>>n;
	for(int i=1; i<=n; i++) {
		cin>>a[i];
		ans|=a[i];
	}
	cout<<ans;
	return 0;
}
J (10). Mov

模拟题,没啥好说的

#include<bits/stdc++.h>
using namespace std;

int n;
string s,t;
int a[1000001];

int main() {
	cin>>n;
	while(n--) {
		cin>>s>>t;
		//cout<<t;
		int x=0;
		if(s[0]=='C')
			continue;
		if(s[0]=='M') {
			int i;
			for(i=0; t[i]!=','; i++)
				x=x*10+t[i]-'0';
			if(t[i+1]<'0'||t[i+1]>'9') {
				int y=0;
				for(int j=i+2; j<t.size(); j++)
					y=y*10+t[j]-'0';
				if(t[i+1]=='#')
					a[x]=y;
				if(t[i+1]=='!')
					a[x]=a[y];
				if(t[i+1]=='@')
					a[x]=a[a[y]];
			} else {
				int y=0;
				for(int j=i+1; j<t.size(); j++)
					y=y*10+t[j]-'0';
				a[x]=a[y];
			}
			//cout<<a[x]<<"\n";
		} else {
			int y=0;
			for(int i=0; i<t.size(); i++)
				y=y*10+t[i]-'0';
			cout<<a[y]<<"\n";
		}
	}
	return 0;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

panjyash

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值