2022年蓝桥杯省赛 C++ A组

A.裁纸刀(找规律)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll res=4;
int main(){
	/*int n,m;
	cin>>n>>m;
	res+=n-1;
	res+=(m-1)*n;
	cout<<res;
	*/
	cout<<443;
	return 0;
} 

B.灭鼠先锋(博弈论)

        注意必败态的判别条件,这里必败态是只剩一个地方没放,和放石子不同,放石子是放满了才是必败态,注意区别!!!所以这里要手动统计还剩的地方,判断是否为必败态 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
map<string,int> f;
int check(string s){
	int t=0;
	for(int i=0;i<8;i++){
		if(s[i]=='0') t++;
	}
	return t;
}
int sg(string x){
	if(f.count(x)) return f[x];
	//x为必败态 
	if(check(x)==1){
		f[x]=0;
		return f[x];
	}
	set<int> st;
	//放一个 
	for(int i=0;i<8;i++){
		if(x[i]=='X') continue;
		string t=x;
		t[i]='X';
		st.insert(sg(t));
	}
	//放两个
	for(int i=0;i+1<=3;i++){
		if(x[i]=='X'||x[i+1]=='X') continue;
		string t=x;
		t[i]='X';
		t[i+1]='X';
		st.insert(sg(t));
	} 
	for(int i=4;i+1<=7;i++){
		if(x[i]=='X'||x[i+1]=='X') continue;
		string t=x;
		t[i]='X';
		t[i+1]='X';
		st.insert(sg(t));
	} 
	for(int i=0;;i++){
		if(!st.count(i)){
			f[x]=i;
			break;
		}
	}
	return f[x];
}
int main(){
	/*string s[]={"X0000000","XX000000","0X000000","0XX00000"};
	for(int i=0;i<4;i++){
		//先手走了一步
		//先手后手转换 sg=0 先手必胜 
		if(sg(s[i])==0) cout<<"V";
		else cout<<"L";
	}*/ 
	cout<<"LLLV"; 
	return 0;
} 

C.求和(前缀和)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
ll res;
ll w[N];
ll sum[N];
int n;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%lld",&w[i]);
		sum[i]=sum[i-1]+w[i];
	}
	for(int i=1;i<=n;i++){
		res+=w[i]*(sum[n]-sum[i]);
	}
	printf("%lld",res);
} 

D.选数异或(思维)

        判断[l,r]之间是否有两个数异或等于x,等价是否存在一个数t,在区间内同时存在t^x

① 用pos[i]记录i上次出现的位置

② 用left[i]记录在w[i]左侧,且与w[i]匹配的最近的数的位置

        遍历[l,r],判断是否存在left[i]>=l即可(可能超时,正确做法是用线段树,维护区间内left的最大值,判断[l,r]内left最大值是否>=l)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
ll w[N];
int n,m;
ll x;
unordered_map<ll,int> pos;//上次出现的位置
int left_[N];//i左边最近的满足要求的数的位置 
int main(){
	scanf("%d%d%lld",&n,&m,&x);
	for(int i=1;i<=n;i++){
		scanf("%lld",&w[i]);
		pos[w[i]]=i; 
		left_[i]=pos[w[i]^x];
	}
	while(m--){
		int l,r;
		scanf("%d%d",&l,&r);
		bool f=false;
		for(int i=l;i<=r;i++){
			if(left_[i]>=l){
				f=true;
				break;
			}
		}
		if(f) printf("yes\n");
		else printf("no\n");
	}
} 

线段树维护

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
#define fast(); ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const int N=1e5+5;
int n,m;
ll A[N],x;
unordered_map<ll,int> pos;//某个数上次出现的位置 
int left_[N];//left_[i] 左边最近的满足的数的位置 
struct node{
	int l,r;
	int maxn;
}tr[N<<2];
void pushup(int u){
	tr[u].maxn=max(tr[u<<1].maxn,tr[u<<1|1].maxn);
}
void build(int u,int l,int r){
	if(l==r){
		tr[u].l=tr[u].r=l;
		tr[u].maxn=left_[l];
		return;
	}
	tr[u].l=l;
	tr[u].r=r;
	int mid=l+r>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	pushup(u);
}
//求l,r的left[i]的最大值 
int query(int u,int l,int r){
	if(tr[u].l>=l&&tr[u].r<=r) return tr[u].maxn;
	int mid=tr[u].l+tr[u].r>>1;
	int maxn=0;  
	if(mid>=l) maxn=max(maxn,query(u<<1,l,r));
	if(mid<r) maxn=max(maxn,query(u<<1|1,l,r));
	return maxn;
}
int main(){
	scanf("%d%d%lld",&n,&m,&x);
	for(int i=1;i<=n;i++){
		scanf("%d",&A[i]);
		pos[A[i]]=i;
		left_[i]=pos[A[i]^x];
	}
	build(1,1,n);
	while(m--){
		int l,r;
		scanf("%d%d",&l,&r);
		int res=query(1,l,r);
		if(res>=l) printf("yes\n");
		else printf("no\n");
	}
} 

E.爬树的甲壳虫(概率期望推导+逆元)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e5+5,mod=998244353;
int n;
ll xx[N],yy[N];
ll qmi(ll a,ll k){
	ll res=1;
	while(k){
		if(k&1) res=res*a%mod;
		a=a*a%mod;
		k>>=1;
	}
	return res;
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>xx[i]>>yy[i];
	}
	ll res=0,d=1;
	for(int i=n;i>=1;i--){
		ll x=xx[i],y=yy[i];
		d=(d*y)%mod;
		d=d*qmi(y-x,mod-2)%mod;
		res=(res+d)%mod;
	}
	cout<<res;
} 
 

F.青蛙过河(二分)

        枚举区间长度L,check为判断所有长度为L的区间和是否全不小于2x,二分枚举满足要求的最大区间长度

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
int n,x;
int h[N];
ll sum[N];
bool check(int mid){
	for(int i=1;i+mid-1<n;i++){
		int j=i+mid-1;
		if(sum[j]-sum[i-1]<(ll)2*x) return false;
	}
	return true;
}
int main(){
	scanf("%d%d",&n,&x);
	for(int i=1;i<n;i++){
		scanf("%d",&h[i]);
		sum[i]=sum[i-1]+h[i];
	}
	int l=0,r=n-1;
	while(l<r){
		int mid=l+r>>1;
		if(check(mid)){
			r=mid;
		}else{
			l=mid+1;
		}
	}
	cout<<l<<endl;
	
} 

G.最长不下降子序列(上升子序列+线段树)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e5+5;
int dp1[N];//以a[i]结尾的最长不下降子序列的长度
int dp2[N];//以a[i]开头的最长不下降子序列的长度
int a[N],b[N];
int n,k;
int res,m;
struct node{
	int l,r;
	int maxn;
}tr[N<<2];
void pushup(int u){
	tr[u].maxn=max(tr[u<<1].maxn,tr[u<<1|1].maxn);
}
void build(int u,int l,int r){
	if(l==r){
		tr[u]={l,r,0};
	}else{
		tr[u]={l,r};
		int mid=l+r>>1;
		build(u<<1,l,mid);
		build(u<<1|1,mid+1,r);
		pushup(u);
	}
}
void modify(int u,int pos,int val){
	if(tr[u].l==tr[u].r) tr[u].maxn=max(tr[u].maxn,val);
	else{
		int mid=tr[u].l+tr[u].r>>1;
		if(pos<=mid) modify(u<<1,pos,val);
		else modify(u<<1|1,pos,val);
		pushup(u);
	}
}
int query(int u,int l,int r){
	if(tr[u].l>=l&&tr[u].r<=r) return tr[u].maxn;
	int mid=tr[u].l+tr[u].r>>1;
	int maxn=-1;
	if(l<=mid) maxn=max(maxn,query(u<<1,l,r));
	else maxn=max(maxn,query(u<<1|1,l,r));
	return maxn;
}
int main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		b[i]=a[i];
	}
	sort(b+1,b+n+1);
	if(n==k){
		cout<<n;
		return 0;
	}
	m=unique(b+1,b+n+1)-(b+1);
	for(int i=1;i<=n;i++){
		int l=1,r=m;
		while(l<r){
			int mid=l+r>>1;
			if(b[mid]>=a[i]) r=mid;
			else l=mid+1; 
		}
		a[i]=l;
	}
	build(1,1,m);
	//从前往后,查在a[i]前,且比a[i]小的,dp1的最大值 
	for(int i=1;i<=n-k;i++){
		dp1[i]=query(1,1,a[i])+1;
		modify(1,a[i],dp1[i]);
	}
	build(1,1,m);
	//从后往前,查在a[i]后,且比a[i]大的,dp2的最大值 
	for(int i=n;i>=k+1;i--){
		res=max(res,dp1[i-k]+k+query(1,a[i-k],m));
		dp2[i]=query(1,a[i],m)+1;
		modify(1,a[i],dp2[i]);
	}
	for(int i=1;i<=n-k;i++){
		res=max(res,dp1[i]+k);
	}
	for(int i=n;i>=k+1;i--){
		res=max(res,dp2[i]+k);
	}
	cout<<res;
} 
 

H.扫描游戏(几何)

        根据象限和斜率,按照顺时针排序,模拟

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=2e5+5;
int res[N],idx;
struct node{
    ll x,y,z;
    double h;
    int pos;
};
int n;
ll L;
vector<node> vc;
bool cmp(node a,node b){
    if((ll)a.x*b.x<0) return a.x>b.x;
    double ka,kb;
    if(a.x==0){
        if(a.y>=0) ka=1e9;
        else ka=-1e9;
    }else{
        ka=a.y*1.0/a.x;
    }
    if(b.x==0){
        if(b.y>=0) kb=1e9;
        else kb=-1e9;
    }else{
        kb=b.y*1.0/b.x;
    }
    return ka>kb;
}
int main(){
    scanf("%d%lld",&n,&L);
    memset(res,-1,sizeof res);
    for(int i=1;i<=n;i++){
        ll x,y,z;scanf("%lld%lld%lld",&x,&y,&z);
        node t={x,y,z,(double)sqrt(x*x*1.0+y*y*1.0),i};
        vc.push_back(t);
    }
    int cnt=0;
    do{
        vector<node> ne;
        sort(vc.begin(),vc.end(),cmp);
        double kk=1e-18;
        for(int i=0;i<vc.size();i++){
            node t=vc[i];
            if(t.h<=L){
                double k;
                if(t.x==0) k=-1e9;
                else k=t.y*1.0/t.x;
                if(k!=kk){
                    res[t.pos]=++idx;
                }else{
                    res[t.pos]=idx++;
                }
                kk=k;
                L+=t.z;
            }else{
                ne.push_back(t); 
            }
        }
        if(vc.size()==ne.size()) cnt++;
        else cnt=0;
        vc=ne;
    }while(cnt<=2);
    for(int i=1;i<=n;i++){
        printf("%d",res[i]);
        if(i!=n) printf(" ");
    }
} 
 

I.数的拆分(质数)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=4005;
int prime[N];
int cnt;
bool vis[N];
void init(){
	for(int i=2;i<N;i++){
		if(!vis[i]){
			prime[++cnt]=i;
		}
		for(int j=1;prime[j]*i<N;j++){
			vis[prime[j]*i]=true;
			if(i%prime[j]==0) break;
		}
	}
}
//判断是否是平方数/立方数 
bool check(ll x){
	if((ll)sqrt(x)*sqrt(x)==x) return true;
	int l=1,r=2e6;
	while(l<r){
		int mid=l+r>>1;
		if((ll)mid*mid*mid>=x) r=mid;
		else l=mid+1;
	}
	if((ll)l*l*l==x) return true;
	return false;
}
int main(){
	init();
	int t;cin>>t;
	while(t--){
		ll x;cin>>x;
		if(check(x)){
			cout<<"yes"<<endl;
			continue;
		}
		bool f=true;
		for(int i=1;i<=cnt;i++){
			if(x%prime[i]==0){
				int s=0;
				while(x%prime[i]==0){
					s++;
					x/=prime[i];
				}
				if(s<2){
					f=false;
					break;
				}
			}
		}
		if(f&&check(x)){
			cout<<"yes"<<endl;
		}else{
			cout<<"no"<<endl;
		}
	}
} 
 

J.推导部分和(差分约束+并查集)

        根据等式建立差分约束,并查集记录两点间是否有约束关系

对于一个点x,如果还未被访问过,说明发现新的约束点集合,点x是集合内编号最小的点,从点x开始bfs求的集合内点到x的距离

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N=1e5+5,M=N<<1;
int h[N],e[M],ne[M],idx;
ll w[M];
int p[N];
int find(int x){
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}
int n,m,q;
void add(int a,int b,ll c){
    e[idx]=b;
    w[idx]=c;
    ne[idx]=h[a];
    h[a]=idx++;
}
ll dis[N];
bool vis[N];
void bfs(int st){
    queue<int> q;
    vis[st]=true;
    dis[st]=0;
    q.push(st);
    while(!q.empty()){
        int t=q.front();q.pop();
        for(int i=h[t];~i;i=ne[i]){
            int j=e[i];
            if(vis[j]) continue;
            vis[j]=true;
            dis[j]=dis[t]+w[i];
            q.push(j);
        }
    }
}
int main(){
    cin>>n>>m>>q;
    memset(h,-1,sizeof h);
    for(int i=0;i<=n;i++) p[i]=i;
    for(int i=1;i<=m;i++){
        int l,r;ll s;cin>>l>>r>>s;
        add(l-1,r,s);
        add(r,l-1,-s);
        p[find(l-1)]=find(r);
    }
    for(int i=0;i<=n;i++){
        if(!vis[i]){
            bfs(i);
        }
    }
    while(q--){
        int l,r;cin>>l>>r;
        if(find(l-1)!=find(r)) cout<<"UNKNOWN\n";
        else{
            ll res=dis[r]-dis[l-1];
            cout<<res<<endl;
        }
    }
} 
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Vic.GoodLuck

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

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

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

打赏作者

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

抵扣说明:

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

余额充值