Acwing蓝桥杯集训·题解week4

AcWing 5589. 哞语言逻辑

大模拟,思路简单,但是实现时要注意代码写的不要混乱,严格执行思路

and优先级高于or,所以可以讲连着的and分成一块,然后统计0,1的数量前缀和,减少时间复杂度

更多细节:视频题解

代码来源以及注释

点击查看代码
#include<bits/stdc++.h>

using namespace std;

const int N=2e5+10;

int n,m;
//q表示用0 1 数字表示true  and (为1),false or(为0),因为奇偶关系,所以相互独立
//id表示现在是第几段,l,r表示每一段的左右边界,cnt表示现在所处的段
int q[N],id[N],l[N],r[N],cnt;
int ones[N];//ones[cnt]表示前cnt段有多少个1(前缀和表示)
int zeroes[N];//表示每一段内到他的左边界有多少个0

int main(){

    char str[10];

    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",str);
        //strcmp相等的话返回的值是0,非0表示正确
        if(!strcmp(str,"true")||!strcmp(str,"or"))q[i]=1;
        //i为奇数,就是一个关键词
        if(i&1){
            //为第一个数或者前一个为or,即表示and段的开头
            if(i==1||q[i-1]){
                cnt++;//段数加1
                l[cnt]=i;//这段左边界为i;
                r[cnt-1]=i-2;//前一段右边界为i-2
                //段落数大于2,就可以开始维护ones了,cnt-1表示为cnt-2段+是否为1
                                        //第cnt-1段的最后一个数(即i-2)就表示这一段有多少0,有0为0,没0为1,故取反
                if(cnt>=2)ones[cnt-1]=ones[cnt-2]+!zeroes[i-2];
                //当前数为1表示没有0
                zeroes[i]=!q[i];
            }
            else//表示段内的前缀和
            zeroes[i]=zeroes[i-2]+!q[i];//隔一个为布尔值
                id[i]=cnt;//表示当前值在第cnt段内

        }
    }
    //终点的前缀和为n
    r[cnt]=n;
    //维护一下最后一个段,也是看最后一个数
    ones[cnt]=ones[cnt-1]+!zeroes[n];
    while(m--){
        int left,right;
        scanf("%d%d%s",&left,&right,str);
        //是为1,不是为0
        bool res=!strcmp(str,"true");
        //看左右分别插在了哪一个段内
        int lid=id[left],rid=id[right];
        //看与插入部分不相关的部分,是1还是0,分左右两个部分
        int a=ones[lid-1]+ones[cnt]-ones[rid];
        int b=zeroes[r[rid]]-zeroes[right];
        if(l[lid]!=left)b+=zeroes[left-2];
        if(res==(a||!b&&true)||res==(a||!b&&false))printf("Y");
        else printf("N");
    }
    return 0;
}

AcWing 5590. 沿栅栏散步

乍看有点复杂,但其实适当转化后,思路就很简单,最终的路径会形成一个环,我们任意选择一个起点,沿着形成的路径,记录到达每一步所需的步数.
用二维数组记录每一个坐标对应从起点到该点的步数,由于是环,最后比较,从那一边过来所需的步数最小

点击查看代码
#include<bits/stdc++.h>

using namespace std;
#define x first
#define y second

typedef pair<int,int> pii;
const int maxn=2e5+10;
const int maxm=1e3+10;

int s[maxm][maxm];
pii q[maxn];
int n,m; 
int get(int x,int tx){
	if(tx>x) 
		return 1;
	if(tx<x) 
		return -1;
	return 0; 
}
void solve(){
	cin>>m>>n;
	for(int i=1;i<=n;++i)
		cin>>q[i].x>>q[i].y;
		
	int sum=0,x=q[n].x,y=q[n].y;
	
	for(int i=1;i<=n;++i){
		int tx=q[i].x,ty=q[i].y;
		int vx=get(x,tx),vy=get(y,ty);
		while(x!=tx || y!=ty){
			x+=vx,y+=vy;
			s[x][y]=++sum;
		}
	}
	while(m--){
		pii a,b;
		cin>>a.x>>a.y>>b.x>>b.y;
		int dis=s[b.x][b.y]-s[a.x][a.y];
		if(dis<0){
			dis+=sum;
		} 
		cout<<min(dis,sum-dis)<<endl;
	}return ;
}
int main(){
	int t=1;
	while(t--){
		solve();
	}
	return 0;
}

AcWing 4888. 领导者

分类讨论
其实也就2种情况

对于一个品种的牛要想成为领导者

  1. 它包含的另一个品种的牛是领导者,当且仅当这个牛满足另一个品种的牛包含其同品种所有牛
  2. 该牛包含其品种的所有牛,另一个品种的牛也包含其全部同品种牛
点击查看代码
#include<bits/stdc++.h>

using namespace std;
int n;
string s;
const int maxn=1e5+10;
int e[maxn];
int rh=0,rg=0;
int lh,lg;
int sh[maxn],sg[maxn];
int ysh=-1,ysg=-1; 
int main(){
    cin>>n>>s;s=" "+s;
    for(int i=1;i<=n;++i) cin>>e[i];
    for(int i=1;i<=n;++i){//找出最右边的牛
        if(s[i]=='H') rh=i;
        if(s[i]=='G') rg=i;
    }
    for(int i=1;i<=n;++i) //检查最左边的牛是否包括所有同品种的牛
        if(s[i]=='H' ) {
            lh=i;
            if(e[i]>=rh) ysh=i;//当前i是包括所有同品种的牛
            break;
        }
    for(int i=1;i<=n;++i){
        if(s[i]=='G' ) {
            lg=i;
            if(e[i]>=rg) ysg=i;
            break;
        }
    }
    int ans=0;
    for(int i=1;i<=n;++i){//条件啊
        if(s[i]=='H')
            if((ysg>i && e[i]>=ysg ) || (i==lh && rh<=e[i] && ysg>i)) ++ans;
        if(s[i]=='G')
            if((ysh>i && e[i]>=ysh ) || (i==lg  && rg<=e[i] && ysh>i)) ++ans;
        
        
    }
    cout<<ans<<endl;
    return 0;
}

https://www.acwing.com/problem/content/4892/

解法有点花里胡哨,二进制枚举+差分

鉴于范围很小,m台空调就用长度为m的二进制数表示,第i个位置有1,就代表第i个空调打开,所以总的有\(2^m\)个方案,从0枚举到\(2^m-1\)

因为降温都相同,所以可以用差分处理,最后从头开始累加,检验每个位置是否满足要求

点击查看代码
#include<bits/stdc++.h>

using namespace std;

int n,m;
const int maxn=22;
int stdtem[110];
struct node1{
    int a,b,p,m;
}kt[maxn];
int quick_pow(int a,int b){
    int ans=1;
    while(b){
        if(b&1) ans*=a;
        a*=a;
        b>>=1;
    }return ans;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;++i){
        int l,r,c;cin>>l>>r>>c;
        for(int i=l;i<=r;++i)    stdtem[i]=max(stdtem[i],c);
    }
        
    for(int i=0;i<m;++i)
        cin>>kt[i].a>>kt[i].b>>kt[i].p>>kt[i].m;
    int tot=quick_pow(2,m);
    int ans=1e9+10;
    
    for(int i=1;i<tot;++i){
        int tem[110],cnt=0;
        memset(tem,0,sizeof(tem));
        bitset<20>binary(i);
        for(int j=0;j<m;++j){
            if(binary[j]){
                tem[kt[j].a]+=kt[j].p;
                tem[kt[j].b+1]-=kt[j].p;
                cnt+=kt[j].m;
            }
        }
        int now=0;
        bool book=0;
        for(int i=1;i<=100;++i){
            now+=tem[i];
            if(now<stdtem[i]){
                book=1;
                break;
            }
        }
        if(!book) ans=min(ans,cnt);
    }
    cout<<ans<<endl;
}

AcWing 4905. 面包店

很有意思,遇到过好几次,不等式求交集
同时你会发现一点,时间越少,一定越能满足客人要求

但是这里有个问题在于有两个变量.

这个时候二分就能妙用,二分减少的总时间z,设减少其中一种制备饼干的时间为x,则另一种减少制备饼干的时间为z-x,解不等式,去检验制备饼干的时间x是否存在,存在则说明z比较还能减小

详细题解

点击查看代码
#include<bits/stdc++.h>

using namespace std;
#define ll long long 

int t;
const int maxn=110;
int n;
int x,y;

struct node{
    ll a,b,c;
}e[maxn];
bool check(ll mid){
    ll minn=max(0ll,1+mid-y),maxx=min(mid,x-1ll);
    for(int i=1;i<=n;++i){
        long double l=e[i].b-e[i].a;
        long double r=e[i].c-(long double)e[i].a*x-(long double)e[i].b*(y-mid);
        if(l==0 && r<0) return false;
        else if(l>0) maxx=min(maxx,(ll)floor(r/l));
        else if(l<0) minn=max(minn,(ll)ceil(r/l));
    }
    return minn<=maxx;
}
void solve(){
    cin>>n>>x>>y;
    for(int i=1;i<=n;++i) cin>>e[i].a>>e[i].b>>e[i].c;
    ll l=0,r=x+y-2;
    while(l<=r){
        ll mid=(l+r)>>1;
        if(check(mid)) r=mid-1;
        else l=mid+1;
    }
    cout<<l<<endl;
    return ;
}
int main(){
    cin>>t;
    while(t--){
        solve();
    }return 0;
}
posted @ 2025-04-01 20:52  归游  阅读(29)  评论(0)    收藏  举报