第29次CSP认证 2022/3/29 个人题解

第29次CSP认证 2022/3/29 个人题解

425分,前三题100,第四题90,第五题35。第四题离散化线段树,测试点10和11过不去,可能出了小bug,要是大伙有看出来什么问题的可以和我说下。

田地丈量

就所有坐标枚举硬怼,感觉复杂度有超的可能,但是过了就没管

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
int multi=false;
const int N=1e4+13; 
int mp[N][N];
void solve(){
	int n,a,b;cin>>n>>a>>b;
	for(int i=1;i<=n;i++){
		int x1,y1,x2,y2;
		cin>>x1>>y1>>x2>>y2;
		for(int i1=max(0,x1);i1<=x2-1;i1++)
			for(int j1=max(0,y1);j1<=y2-1;j1++)mp[i1][j1]=1;
	}
	int res=0;
	for(int i=0;i<a;i++)for(int j=0;j<b;j++)if(mp[i][j])res++;
	cout<<res<<endl;
}
signed main(){
	int t=1;
	if(multi)cin>>t;
	while(t--)solve();
	
} 
/*
4 10 10
0 0 5 5
5 -2 15 3
8 8 15 15
-2 10 3 15
*/

垦田计划

小小的二分一下

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
int multi=false; 
const int N=1e5+13;
int t[N],c[N];
int n,m,k;
bool check(int x){
	int res=0;
	for(int i=1;i<=n;i++){
		if(t[i]>=x)res+=c[i]*(t[i]-x);
	}
	//cout<<x<<" "<<res<<endl;
	if(res>m)return false;
	return true;
}
void solve(){
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)cin>>t[i]>>c[i];
	int l=k,r=*max_element(t+1,t+1+n);
	while(l<r){
		int mid=l+r>>1;
		if(check(mid))r=mid;
		else l=mid+1;
	}
	cout<<l<<endl;
}
signed main(){
	int t=1;
	if(multi)cin>>t;
	while(t--)solve();
} 
/*
4 9 2
6 1
5 1
6 2
7 1
*/

LDAP

模拟的很痛苦,大体思路就是先把字符串递归出所有条件,然后再进行枚举。写的不好,不开unordered_map只能过70分,开了能水过,还好数据没搞那种卡n2的玩意,不然这场炸了。

#include<iostream>
#include<map>
#include<vector>
#include<algorithm>
#include<unordered_map> 
using namespace std;
#define endl "\n"
int multi=false; 
int n,dn[2502];
unordered_map<int,int> mp[2502];
bool ok(string s,int x){
	if(s[0]=='|'){
		string s1,s2;
		int idx=0,stk=0;
		for(int i=1;i<s.size();i++){
			if(s[i]==')'){
				if(--stk==0){
					idx=i;break;
				}
			}else if(s[i]=='(')stk++;
		}
		s1=s.substr(2,idx-2);
		s2=s.substr(idx+2);//cout<<s2<<endl;
		s2=s2.substr(0,s2.size()-1);//cout<<s2<<endl;
		if(ok(s1,x)||ok(s2,x))return true;
		return false;
	}else if(s[0]=='&'){
		string s1,s2;
		int idx=0,stk=0;
		for(int i=0;i<s.size();i++){
			if(s[i]==')'){
				if(--stk==0){
					idx=i;break;
				}
			}else if(s[i]=='(')stk++;
		}
		s1=s.substr(2,idx-2);
		s2=s.substr(idx+2);
		s2=s2.substr(0,s2.size()-1);
		if(ok(s1,x)&&ok(s2,x))return true;return false;
	}else{
		int split=s.find(":");
		if(split!=s.npos){
			//cout<<split<<" "<<s.substr(0,split)<<" "<<s.substr(split+1);
			int val1=stoi(s.substr(0,split)),val2=stoi(s.substr(split+1));
			if(mp[x][val1]==val2)return true;return false;
		}else{
			split=s.find("~");
			int val1=stoi(s.substr(0,split)),val2=stoi(s.substr(split+1));
			if(mp[x][val1]!=val2&&mp[x][val1]!=0)return true;return false;
		}
	}
}
void solve(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>dn[i];
		int cnt;cin>>cnt;
		for(int j=1;j<=cnt;j++){
			int a,b;cin>>a>>b;
			mp[i][a]=b;
		}
	}
	int q;cin>>q;
	while(q--){
		string s;cin>>s;
		vector<int> ans;
		for(int i=1;i<=n;i++)if(ok(s,i))ans.push_back(dn[i]);
		//for(auto& v:res)cout<<v<<" "<<dn[v]<<endl;
		sort(ans.begin(),ans.end());
		for(int i=0;i<ans.size();i++)cout<<ans[i]<<" \n"[i==int(ans.size())-1];
		if(ans.size()==0)cout<<endl;
	}
}
signed main(){
	ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
	int t=1;
	if(multi)cin>>t;
	while(t--)solve();
} 
/*
2
1 2 1 2 2 3
2 2 2 3 3 1
40
1:2
3~1
&(1:2)(2:3)
|(1:2)(3:1)
|(3~1)(3:1)
&(&(1:2)(2:3))(3:1)

*/

星际网络II 90分

看这样子就像线段树,数据范围这么大,所以肯定需要离散化。输入格式很怪,很明显不能用long long存。好在都是定长字符串,字符串直接比大小没有问题。然后需要先把所有query出现的数据都存进去,所以要先读一遍query,把query的内容存到一个vector里,然后再读vector,写的也很难受。我用的是map存储,也可以lower_bound,可能会快一点?然后把离散化以后的点进行线段树的基本操作就行了,线段树写起来还是很快的。当然这里有个小细节,如果两个相邻的数字差值大于1,那么就需要在这两个数之间插入一个点来防止出现问题。细节看代码

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
int multi=false; 
const int N=2e5+3;
set<string> s;
map<string,int> mp;
int nowsz;
struct tree{
	int col,difcol,lz,sz;
}t[N<<2];
void pushup(int id){
	if(t[id<<1].col==t[id<<1|1].col||(t[id<<1].col==0||t[id<<1|1].col==0)){
		t[id].difcol=t[id<<1].difcol|t[id<<1|1].difcol;
	}else t[id].difcol=1;
	if(t[id].difcol==1)t[id].col=0x3f3f3f3f;
	else t[id].col=t[id<<1].col|t[id<<1|1].col;//may has problem?
	t[id].sz=t[id<<1].sz+t[id<<1|1].sz;
}
void pushdown(int l,int r,int id){
	int mid=l+r>>1;
	if(t[id].lz){
		int col=t[id].lz;t[id].lz=0;
		t[id<<1].col=t[id<<1|1].col=col;
		t[id<<1].difcol=t[id<<1|1].difcol=0;
		t[id<<1].lz=t[id<<1|1].lz=col;
		t[id<<1].sz=mid-l+1;t[id<<1|1].sz=r-mid;
	}
}
bool queryok(int x,int y,int z,int l,int r,int id){
	if(l>=x&r<=y){
		nowsz+=t[id].sz;
		if(t[id].col!=z&&t[id].col!=0)return false;
		return true;
	}
	int mid=l+r>>1;
	pushdown(l,r,id);
	int res=1;
	if(x<=mid)res&=queryok(x,y,z,l,mid,id<<1);
	if(y>mid)res&=queryok(x,y,z,mid+1,r,id<<1|1);
	return res;
}
void update(int x,int y,int z,int l,int r,int id){
	if(l>=x&&r<=y){
		t[id].col=z;t[id].lz=z;t[id].difcol=0;t[id].sz=r-l+1;return ;
	}
	int mid=l+r>>1;
	pushdown(l,r,id);
	if(x<=mid)update(x,y,z,l,mid,id<<1);
	if(y>mid)update(x,y,z,mid+1,r,id<<1|1);
	pushup(id);
}
int query(int x,int l,int r,int id){
	if(l==r){
		return t[id].col;
	}
	int mid=l+r>>1;
	pushdown(l,r,id);
	if(x<=mid)return query(x,l,mid,id<<1);
	else return query(x,mid+1,r,id<<1|1);
}
int query(int x,int y,int l,int r,int id){
	if(l>=x&&r<=y){
		nowsz+=t[id].sz;
		return t[id].col;
	}
	int mid=l+r>>1;
	pushdown(l,r,id);
	int res1=-1,res2=-1;
	if(x<=mid)res1=query(x,y,l,mid,id<<1);
	if(y>mid)res2=query(x,y,mid+1,r,id<<1|1);
	if(res1!=-1&&res2!=-1&&res1!=res2){
		return 0;
	}else if(res1==res2)return res1;
	else if(res1!=-1)return res1;
	else return res2;
}
void solve(){
	int n,q;cin>>n>>q;
	vector<vector<int> > lst;
	vector<vector<string>> lst2;
	for(int i=1;i<=q;i++){
		vector<int> lstt;
		vector<string> lstt2;
		int op;cin>>op;lstt.push_back(op);
		if(op==1){
			int col;cin>>col;lstt.push_back(col);
			string l,r;cin>>l>>r;
			s.insert(l);s.insert(r);
			lstt2.push_back(l);lstt2.push_back(r);
		}else if(op==2){
			string x;cin>>x;
			s.insert(x);lstt2.push_back(x);
		}else{
			string l,r;cin>>l>>r;
			s.insert(l);s.insert(r);
			lstt2.push_back(l);lstt2.push_back(r);
		}
		lst.push_back(lstt);lst2.push_back(lstt2);
	}
	int cnt=0;
	for(auto& v:s){
		++cnt;mp[v]=++cnt;
	}
	int len=cnt;
	for(int i=0;i<lst2.size();i++){
		for(auto& s:lst2[i])lst[i].push_back(mp[s]);
	}
	for(int i=0;i<q;i++){
		vector<int> lstt=lst[i];
		int op=lstt[0];
		if(op==1){
			int col=lstt[1],l=lstt[2],r=lstt[3];
			nowsz=0;
			if(queryok(l,r,col,1,len,1)&&nowsz!=r-l+1){
				cout<<"YES"<<endl;
				//cout<<l<<" "<<r<<" "<<col;
				update(l,r,col,1,len,1);
				//cout<<" "<<t[1].col<<endl;
			}else{
				cout<<"NO"<<endl;
			}
		}else if(op==2){
			int x=lstt[1];
			int res=query(x,1,len,1);assert(res!=0x3f3f3f3f);
			cout<<res<<endl;
		}else{
			nowsz=0;
			int l=lstt[1],r=lstt[2];
			int res=query(l,r,1,len,1);
			if(res==0||res==-1||res==0x3f3f3f3f||nowsz!=r-l+1)cout<<0<<endl;
			else cout<<res<<endl;
			//cout<<"fk"<<nowsz<<endl;
		}
	}
}
signed main(){
	int t=1;
	if(multi)cin>>t;
	while(t--)solve();
} 

施肥 35分

不想做最后一题,反正也不是我能做出来的,所以就打了个暴力,水了35分,大体思路就是枚举l,r,然后再遍历一遍所有车子,车子在l,r范围内的就把那个区间加上1,最后查询区间最小值是不是大于0即可。后面了解到可以水到60分,大概思路也是枚举l,r,不是遍历一遍所有车子,而是使用双指针类似的方法动态的删减,然后线段树区间加。后悔没多想想,再加上需要返校考试,最后1h只能交卷赶车,所以没写。如果再特判性质A的那15分,可能会拿到75分。100分的解法想不出来。

#include<bits/stdc++.h>
using namespace std;
#define endl "\n"
int multi=false; 
void solve(){
	int n,m;cin>>n>>m;
	vector<pair<int,int> >a;
	for(int i=1;i<=m;i++){
		int u,v;cin>>u>>v;
		a.push_back({u,v});
	}
	int res=0;
	for(int l=1;l<=n;l++){
		for(int r=l;r<=n;r++){
			vector<int> vis(n+1);
			for(int i=1;i<=m;i++){
				if(a[i-1].first>=l&&a[i-1].second<=r){
					for(int x1=a[i-1].first;x1<=a[i-1].second;x1++)
						vis[x1]=1;
				}
			}
			int fg=1;
			for(int i=l;i<=r;i++)if(!vis[i])fg=0;
			if(fg)res++;
		}
	}
	cout<<res<<endl;
}
signed main(){
	int t=1;
	if(multi)cin>>t;
	while(t--)solve();
} 
  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Artificial Retard

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

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

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

打赏作者

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

抵扣说明:

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

余额充值