CSP-J2022试题题解

1.乘方

原题:https://www.luogu.com.cn/problem/P8813

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int XN = 1e9;
ll a,b,ans=1;
int main(){
	cin>>a>>b;
	for(int i=1;i<=b;i++){
		ans*=a;
		if(ans>XN){
			cout<<"-1";
			return 0;
		}
	}
	cout<<ans;
	return 0;
}

 

解题思路:

因为pow的速度太慢,所以要使用累乘的方法去判断

 

2.解密

原题:https://www.luogu.com.cn/problem/P8814

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll k,n,d,e;
vector<ll>vec;
pair<ll,ll>ans;
bool Solve(ll n,ll d,ll e){
	for(ll i=1;i*i<=n;i++){
		if(n%i==0){
			vec.push_back(i);
			if(n/i!=i){
				vec.push_back(n/i);
			}
		}
	}
	for(ll i=0;i<vec.size();i+=2){
		if((vec[i]-1)*(vec[i+1]-1)+1==e*d){
			ans.first=vec[i];
			ans.second=vec[i+1];
			return 1;
		}
	}
	return 0;
}
int main(){
	cin>>k;
	while(k--){
		vec=vector<ll>();
		cin>>n>>d>>e;
		if(Solve(n,d,e))cout<<ans.first<<' '<<ans.second<<'\n';
		else cout<<"NO\n";
	}
	return 0;
}

  

题解代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll k,n,e,d,m;
int main(){
	cin>>k;
	while(k--){
		cin>>n>>e>>d;
		m=n-e*d+2;
		ll l=1,r=m/2;
		while(l<r){
			ll mid=(l+r)>>1;
			if(mid*(m-mid)>=n)r=mid;
			else l=mid+1;
		}
		if(m-r>=1&&r*(m-r)==n)cout<<r<<' '<<m-r<<'\n';
		else cout<<"NO\n";
	}
	return 0;
}

  

解题思路:

计算m,使用二分确定第一个数,通过第一个数可以得出第二个数,注意,这道题的数据特别大,需要开long long

错误原因:

想到过二分,却没有坚持自己的思路去走下去,而是选择了因数分解的方式去解题

 

3.逻辑表达式

原题:https://www.luogu.com.cn/problem/P8815

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 3e6+520;
stack<int>num;
stack<char>op;
int cnt1,cnt2,cnt=0;string s;
struct node{
	char op;
	int l,r;
}tree[N];
void creart(){
	int a=num.top();num.pop();
	int b=num.top();num.pop();
	char c=op.top();op.pop();
	if(c=='&')num.push(a&b);
	else if(c=='|')num.push(a|b);
}
void build(){
	for(int i=0;i<s.length();i++){
		if(s[i]=='(')op.push(s[i]);
		else if(s[i]==')'){
			while(op.top()!='(')creart();
			cnt--;
		}else if(s[i]=='&'){
			tree[++cnt].op='&';
			tree[cnt].l=tree[cnt].r=0;
			op.push(s[i]);
		}else if(s[i]=='|'){
			tree[++cnt].op='|';
			tree[cnt].l=tree[cnt].r=0;
			op.push(s[i]);
		}else{
			tree[++cnt].op=s[i];
			tree[cnt].l=tree[cnt].r=0;
			num.push(s[i]-'0');
		}
	}
}
int dfs(int x){
	if(tree[x].op=='0')return 0;
	if(tree[x].op=='1')return 1;
	if(tree[x].op=='&'){
		if(dfs(tree[x].l)==0){
			cnt1++;
			return 0;
		}else return dfs(tree[x].r);
	}
	if(tree[x].op=='|'){
		if(dfs(tree[x].l)==1){
			cnt2++;
			return 1;
		}else return dfs(tree[x].r);
	}
}
int main(){
	cin>>s;
	build();
	int ans=dfs(cnt);
	cout<<ans<<'\n'<<cnt1<<' '<<cnt2;
	return 0;
}

 

题解代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 3e6+520;
map<char,int>yx;
stack<int>num;
stack<char>op;
int cnt1,cnt2,cnt=0;string s;
struct node{
	char op;
	int l,r;
	node(){};
	node(char opv,int ls,int rs){
		op=opv;
		l=ls;
		r=rs;
	}
	node(char opv){
		op=opv;
	}
}tree[N];
void create(){
	int a=num.top();num.pop();
	int b=num.top();num.pop();
	char c=op.top();op.pop();
	tree[++cnt]=node(c,b,a);
	num.push(cnt);
}
void build(){
	for(int i=0;i<s.length();i++){
		if(s[i]=='(')op.push(s[i]);
		else if(s[i]==')'){
			while(op.top()!='(')create();
			op.pop();
		}else if(s[i]=='&'||s[i]=='|'){
			while(op.size()&&yx[op.top()]>=yx[s[i]])create();
			op.push(s[i]);
		}else{
			tree[++cnt]=node(s[i]);
			num.push(cnt);
		}
	}
	while(op.size())create();
}
int dfs(int x){
	if(tree[x].op=='0')return 0;
	if(tree[x].op=='1')return 1;
	if(tree[x].op=='&'){
		if(dfs(tree[x].l)==0){
			cnt1++;
			return 0;
		}else return dfs(tree[x].r);
	}
	if(dfs(tree[x].l)==1){
		cnt2++;
		return 1;
	}
	return dfs(tree[x].r);
}
int main(){
	yx['(']=0;
	yx['&']=2;
	yx['|']=1;
	cin>>s;
	build();
	
//	for(int i=1;i<=cnt;i++){
//		cout<<tree[i].op<<' '<<tree[i].l<<' '<<tree[i].r<<'\n';
//	}
	
	int ans=dfs(cnt);
	cout<<ans<<'\n'<<cnt1<<' '<<cnt2;
	return 0;
}

  

解题思路:

先读入表达式,建立表达式树,通过深搜计算每个“短路”的个数

错误原因:

建树错误,编号传递错误,导致答案错误,且没有运算符的优先级

 

4.上升点列

原题:https://www.luogu.com.cn/problem/P8816

代码:

#include<bits/stdc++.h>
#define ll long long
#define x first
#define y second
using namespace std;
const int N = 5e2+255;
pair<int,int>a[N];
int n,K,xdp[N],dp[N],ans,xn=0;
int main(){
	cin>>n>>K;
	for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].y;
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++){
		int j=i+1;
		if(a[i].y>a[j].y)continue;
		xdp[j]=abs(a[j].x-a[i].x)+abs(a[j].y-a[i].y)-1;
	}
	for(int i=2;i<=n;i++)if(xdp[i])dp[++xn]=xdp[i];
	n=xn;
	for(int i=1;i<=n;i++)dp[i]+=dp[i-1];
	for(int t=1;t<=n;t++){
		for(int i=1;i<=n;i++){
			int j=i+t-1;
			if(j>n)break;
			ans=max(ans,t+(dp[j]-dp[i-1])+(K-(dp[j]-dp[i-1])));
		}
	}
	cout<<ans;
	return 0;
}

  

题解代码:

#include<bits/stdc++.h>
#define ll long long
#define x first
#define y second
using namespace std;
const int N = 5e2+255;
pair<int,int>a[N];
int n,K,dp[N][N],ans;
int main(){
	cin>>n>>K;
	for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].y;
	sort(a+1,a+n+1);
	for(int i=1;i<=n;i++){
		for(int j=0;j<=K;j++){
			dp[i][j]=1;
			for(int k=1;k<i;k++){
				if(a[i].y<a[k].y)continue;
				int dis=(a[i].x-a[k].x)+(a[i].y-a[k].y)-1;
				if(j>=dis)dp[i][j]=max(dp[i][j],dp[k][j-dis]+dis+1);
			}
			ans=max(ans,dp[i][j]+K-j);
		}
	}
	cout<<ans;
	return 0;
}

  

解题思路:

输入每个点的坐标,进行排序,枚举每种组合,组成dp的数据,计算欧几里得距离,取dp的最大值即为答案

错误原因:

思路错误,原代码是前缀和,题解代码是dp算法,导致“听取WA声一片”

posted @ 2023-05-17 23:45  天雷小兔  阅读(193)  评论(0)    收藏  举报