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声一片”

浙公网安备 33010602011771号