CSP-J2020试题

1.优秀的拆分

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

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e4+255;
ll n,x=0,power[N];
int main(){
	cin>>n;
	if(n%2==1)cout<<"-1";
	else{
		while(n){
			power[++x]=n%2;
			n/=2;
		}
		for(int i=x;i>=1;i--){
			if(power[i]==1)cout<<(ll)(pow(2,i-1))<<' ';
		}
	}
	return 0;
}

  

解题思路:

题目中说n必须由2的正整数次幂组成,1是2的0次幂,所以n不可以是奇数,然后分解成二进制,输出就是答案

 

2.直播获奖

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

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 6e2+255;
int sum[N],n,w,a;
int main(){
	cin>>n>>w;
	for(int i=1;i<=n;i++){
		cin>>a;
		int fx=max(1.0,floor(i*w/100.0));
		sum[a]++;
		for(int j=600;j>=0;j--){
			fx-=sum[j];
			if(fx<=0){
				cout<<j<<' ';
				break;
			}
		}
	}
	return 0;
}

  

解题思路:

大模拟,计算获奖人数,用一个桶统计分数,从600到0,减去每个分数的人数,直到0或0以下为止

注意事项:

1.在计算p*w%时,这个式子等于p/100*w,但在c++中小数乘法会出现精度错误,所以要先乘w再除以100

 

3.表达式

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

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e6+255;
struct nod{
	bool v;int l,r;char op;
}tree[4*N];
int n,q,k,flag[N],cnt;
string s;
void readp(){
	getline(cin,s);
	s+=" ";
	cin>>n;cnt=n;
	for(int i=1;i<=n;i++){
		cin>>tree[i].v;
		tree[i].l=tree[i].r=0;
		tree[i].op='#';
	}
}
void build(){
	stack<int>sta;int t=-1,num1,num2;
	for(int i=0;i<s.length();i++){
		if(s[i]=='x')t=0;
		else if(s[i]>='0'&&s[i]<='9')t=t*10+(s[i]-'0');
		else if(s[i]==' '){
			if(t!=-1){
				sta.push(t);
				t=-1;
			}
		}else if(s[i]=='!'){
			num1=sta.top();sta.pop();
			tree[++cnt].l=num1;
			tree[cnt].op='!';
			tree[cnt].r=0;
			tree[cnt].v=!tree[num1].v;
			sta.push(cnt);
		}else if(s[i]=='&'){
			num2=sta.top();sta.pop();
			num1=sta.top();sta.pop();
			tree[++cnt].l=num1;
			tree[cnt].r=num2;
			tree[cnt].op='&';
			tree[cnt].v=tree[num1].v&tree[num2].v;
			sta.push(cnt);
		}else if(s[i]=='|'){
			num2=sta.top();sta.pop();
			num1=sta.top();sta.pop();
			tree[++cnt].l=num1;
			tree[cnt].r=num2;
			tree[cnt].op='|';
			tree[cnt].v=tree[num1].v|tree[num2].v;
			sta.push(cnt);
		}
	}
}
void dfs(int root){
	flag[root]=1;
	if(tree[root].op=='#')return;
	if(tree[root].op=='!')dfs(tree[root].l);
	if(tree[root].op=='&'){
		if(tree[root].v==0){
			if(tree[tree[root].l].v==1)dfs(tree[root].r);
			else if(tree[tree[root].r].v==1)dfs(tree[root].l);
		}else{
			dfs(tree[root].l);
			dfs(tree[root].r);
		}
	}
	if(tree[root].op=='|'){
		if(tree[root].v==1){
			if(tree[tree[root].l].v==0)dfs(tree[root].r);
			else if(tree[tree[root].r].v==0)dfs(tree[root].l);
		}else{
			dfs(tree[root].l);
			dfs(tree[root].r);
		}
	}
}
int main(){
	readp();
	build();
	dfs(cnt);
	cin>>q;
	while(q--){
		cin>>k;
		if(flag[k])cout<<!tree[cnt].v<<'\n';
		else cout<<tree[cnt].v<<'\n';
	}
	return 0;
}

  

解题思路:

建好表达式树,进行深搜,如果是“!” ,遍历左孩子,如果是“&”或“|”,遍历左孩子和右孩子,遍历到的节点都打上标记,最终输出结果

 

4.方格取数

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

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e3+5;
ll n,m,a[N][N],dp[N][N][3];
ll dfs(ll x,ll y,ll flag){
	if(dp[x][y][flag]!=-1)return dp[x][y][flag];
	if(x==n&&y==m)return dp[x][y][flag]=a[n][m];
	ll ans=-1e10;
	if(y<m)ans=max(ans,dfs(x,y+1,2));
	if(x>1&&flag!=0)ans=max(ans,dfs(x-1,y,1));
	if(x<n&&flag!=1)ans=max(ans,dfs(x+1,y,0));
	return dp[x][y][flag]=ans+a[x][y];
}
int main(){
	memset(dp,-1,sizeof(dp));
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
		}
	}
	cout<<dfs(1,1,2)<<'\n';
	return 0;
}

  

解题思路:运用记忆化剪枝,可以大大降低dfs的复杂度,建立一个flag,用来记录方向,遍历三个方向,取最大值就是答案

注意事项:

1.这道题最后的数据可能会很大,所以要开long long

posted @ 2023-05-18 23:29  天雷小兔  阅读(79)  评论(1)    收藏  举报